roojs-core-debug.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88
89         /**
90          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
91          * @type Boolean
92          */
93         enableGarbageCollector : true,
94
95         /**
96          * True to automatically purge event listeners after uncaching an element (defaults to false).
97          * Note: this only happens if enableGarbageCollector is true.
98          * @type Boolean
99          */
100         enableListenerCollection:false,
101
102         /**
103          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104          * the IE insecure content warning (defaults to javascript:false).
105          * @type String
106          */
107         SSL_SECURE_URL : "javascript:false",
108
109         /**
110          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
112          * @type String
113          */
114         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
115
116         emptyFn : function(){},
117
118         /**
119          * Copies all the properties of config to obj if they don't already exist.
120          * @param {Object} obj The receiver of the properties
121          * @param {Object} config The source of the properties
122          * @return {Object} returns obj
123          */
124         applyIf : function(o, c){
125             if(o && c){
126                 for(var p in c){
127                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
128                 }
129             }
130             return o;
131         },
132
133         /**
134          * Applies event listeners to elements by selectors when the document is ready.
135          * The event name is specified with an @ suffix.
136 <pre><code>
137 Roo.addBehaviors({
138    // add a listener for click on all anchors in element with id foo
139    '#foo a@click' : function(e, t){
140        // do something
141    },
142
143    // add the same listener to multiple selectors (separated by comma BEFORE the @)
144    '#foo a, #bar span.some-class@mouseover' : function(){
145        // do something
146    }
147 });
148 </code></pre>
149          * @param {Object} obj The list of behaviors to apply
150          */
151         addBehaviors : function(o){
152             if(!Roo.isReady){
153                 Roo.onReady(function(){
154                     Roo.addBehaviors(o);
155                 });
156                 return;
157             }
158             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
159             for(var b in o){
160                 var parts = b.split('@');
161                 if(parts[1]){ // for Object prototype breakers
162                     var s = parts[0];
163                     if(!cache[s]){
164                         cache[s] = Roo.select(s);
165                     }
166                     cache[s].on(parts[1], o[b]);
167                 }
168             }
169             cache = null;
170         },
171
172         /**
173          * Generates unique ids. If the element already has an id, it is unchanged
174          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176          * @return {String} The generated Id.
177          */
178         id : function(el, prefix){
179             prefix = prefix || "roo-gen";
180             el = Roo.getDom(el);
181             var id = prefix + (++idSeed);
182             return el ? (el.id ? el.id : (el.id = id)) : id;
183         },
184          
185        
186         /**
187          * Extends one class with another class and optionally overrides members with the passed literal. This class
188          * also adds the function "override()" to the class that can be used to override
189          * members on an instance.
190          * @param {Object} subclass The class inheriting the functionality
191          * @param {Object} superclass The class being extended
192          * @param {Object} overrides (optional) A literal with members
193          * @method extend
194          */
195         extend : function(){
196             // inline overrides
197             var io = function(o){
198                 for(var m in o){
199                     this[m] = o[m];
200                 }
201             };
202             return function(sb, sp, overrides){
203                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
204                     overrides = sp;
205                     sp = sb;
206                     sb = function(){sp.apply(this, arguments);};
207                 }
208                 var F = function(){}, sbp, spp = sp.prototype;
209                 F.prototype = spp;
210                 sbp = sb.prototype = new F();
211                 sbp.constructor=sb;
212                 sb.superclass=spp;
213                 
214                 if(spp.constructor == Object.prototype.constructor){
215                     spp.constructor=sp;
216                    
217                 }
218                 
219                 sb.override = function(o){
220                     Roo.override(sb, o);
221                 };
222                 sbp.override = io;
223                 Roo.override(sb, overrides);
224                 return sb;
225             };
226         }(),
227
228         /**
229          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
230          * Usage:<pre><code>
231 Roo.override(MyClass, {
232     newMethod1: function(){
233         // etc.
234     },
235     newMethod2: function(foo){
236         // etc.
237     }
238 });
239  </code></pre>
240          * @param {Object} origclass The class to override
241          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
242          * containing one or more methods.
243          * @method override
244          */
245         override : function(origclass, overrides){
246             if(overrides){
247                 var p = origclass.prototype;
248                 for(var method in overrides){
249                     p[method] = overrides[method];
250                 }
251             }
252         },
253         /**
254          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
255          * <pre><code>
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
259 </code></pre>
260          * @param {String} namespace1
261          * @param {String} namespace2
262          * @param {String} etc
263          * @method namespace
264          */
265         namespace : function(){
266             var a=arguments, o=null, i, j, d, rt;
267             for (i=0; i<a.length; ++i) {
268                 d=a[i].split(".");
269                 rt = d[0];
270                 /** eval:var:o */
271                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272                 for (j=1; j<d.length; ++j) {
273                     o[d[j]]=o[d[j]] || {};
274                     o=o[d[j]];
275                 }
276             }
277         },
278         /**
279          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
280          * <pre><code>
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
283 </code></pre>
284          * @param {String} classname
285          * @param {String} namespace (optional)
286          * @method factory
287          */
288          
289         factory : function(c, ns)
290         {
291             // no xtype, no ns or c.xns - or forced off by c.xns
292             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
293                 return c;
294             }
295             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296             if (c.constructor == ns[c.xtype]) {// already created...
297                 return c;
298             }
299             if (ns[c.xtype]) {
300                 if (Roo.debug) console.log("Roo.Factory(" + c.xtype + ")");
301                 var ret = new ns[c.xtype](c);
302                 ret.xns = false;
303                 return ret;
304             }
305             c.xns = false; // prevent recursion..
306             return c;
307         },
308          
309         /**
310          * 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.
311          * @param {Object} o
312          * @return {String}
313          */
314         urlEncode : function(o){
315             if(!o){
316                 return "";
317             }
318             var buf = [];
319             for(var key in o){
320                 var ov = o[key], k = encodeURIComponent(key);
321                 var type = typeof ov;
322                 if(type == 'undefined'){
323                     buf.push(k, "=&");
324                 }else if(type != "function" && type != "object"){
325                     buf.push(k, "=", encodeURIComponent(ov), "&");
326                 }else if(ov instanceof Array){
327                     if (ov.length) {
328                             for(var i = 0, len = ov.length; i < len; i++) {
329                                 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
330                             }
331                         } else {
332                             buf.push(k, "=&");
333                         }
334                 }
335             }
336             buf.pop();
337             return buf.join("");
338         },
339
340         /**
341          * 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]}.
342          * @param {String} string
343          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344          * @return {Object} A literal with members
345          */
346         urlDecode : function(string, overwrite){
347             if(!string || !string.length){
348                 return {};
349             }
350             var obj = {};
351             var pairs = string.split('&');
352             var pair, name, value;
353             for(var i = 0, len = pairs.length; i < len; i++){
354                 pair = pairs[i].split('=');
355                 name = decodeURIComponent(pair[0]);
356                 value = decodeURIComponent(pair[1]);
357                 if(overwrite !== true){
358                     if(typeof obj[name] == "undefined"){
359                         obj[name] = value;
360                     }else if(typeof obj[name] == "string"){
361                         obj[name] = [obj[name]];
362                         obj[name].push(value);
363                     }else{
364                         obj[name].push(value);
365                     }
366                 }else{
367                     obj[name] = value;
368                 }
369             }
370             return obj;
371         },
372
373         /**
374          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375          * passed array is not really an array, your function is called once with it.
376          * The supplied function is called with (Object item, Number index, Array allItems).
377          * @param {Array/NodeList/Mixed} array
378          * @param {Function} fn
379          * @param {Object} scope
380          */
381         each : function(array, fn, scope){
382             if(typeof array.length == "undefined" || typeof array == "string"){
383                 array = [array];
384             }
385             for(var i = 0, len = array.length; i < len; i++){
386                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
387             }
388         },
389
390         // deprecated
391         combine : function(){
392             var as = arguments, l = as.length, r = [];
393             for(var i = 0; i < l; i++){
394                 var a = as[i];
395                 if(a instanceof Array){
396                     r = r.concat(a);
397                 }else if(a.length !== undefined && !a.substr){
398                     r = r.concat(Array.prototype.slice.call(a, 0));
399                 }else{
400                     r.push(a);
401                 }
402             }
403             return r;
404         },
405
406         /**
407          * Escapes the passed string for use in a regular expression
408          * @param {String} str
409          * @return {String}
410          */
411         escapeRe : function(s) {
412             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
413         },
414
415         // internal
416         callback : function(cb, scope, args, delay){
417             if(typeof cb == "function"){
418                 if(delay){
419                     cb.defer(delay, scope, args || []);
420                 }else{
421                     cb.apply(scope, args || []);
422                 }
423             }
424         },
425
426         /**
427          * Return the dom node for the passed string (id), dom node, or Roo.Element
428          * @param {String/HTMLElement/Roo.Element} el
429          * @return HTMLElement
430          */
431         getDom : function(el){
432             if(!el){
433                 return null;
434             }
435             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
436         },
437
438         /**
439         * Shorthand for {@link Roo.ComponentMgr#get}
440         * @param {String} id
441         * @return Roo.Component
442         */
443         getCmp : function(id){
444             return Roo.ComponentMgr.get(id);
445         },
446          
447         num : function(v, defaultValue){
448             if(typeof v != 'number'){
449                 return defaultValue;
450             }
451             return v;
452         },
453
454         destroy : function(){
455             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
456                 var as = a[i];
457                 if(as){
458                     if(as.dom){
459                         as.removeAllListeners();
460                         as.remove();
461                         continue;
462                     }
463                     if(typeof as.purgeListeners == 'function'){
464                         as.purgeListeners();
465                     }
466                     if(typeof as.destroy == 'function'){
467                         as.destroy();
468                     }
469                 }
470             }
471         },
472
473         // inpired by a similar function in mootools library
474         /**
475          * Returns the type of object that is passed in. If the object passed in is null or undefined it
476          * return false otherwise it returns one of the following values:<ul>
477          * <li><b>string</b>: If the object passed is a string</li>
478          * <li><b>number</b>: If the object passed is a number</li>
479          * <li><b>boolean</b>: If the object passed is a boolean value</li>
480          * <li><b>function</b>: If the object passed is a function reference</li>
481          * <li><b>object</b>: If the object passed is an object</li>
482          * <li><b>array</b>: If the object passed is an array</li>
483          * <li><b>regexp</b>: If the object passed is a regular expression</li>
484          * <li><b>element</b>: If the object passed is a DOM Element</li>
485          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488          * @param {Mixed} object
489          * @return {String}
490          */
491         type : function(o){
492             if(o === undefined || o === null){
493                 return false;
494             }
495             if(o.htmlElement){
496                 return 'element';
497             }
498             var t = typeof o;
499             if(t == 'object' && o.nodeName) {
500                 switch(o.nodeType) {
501                     case 1: return 'element';
502                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
503                 }
504             }
505             if(t == 'object' || t == 'function') {
506                 switch(o.constructor) {
507                     case Array: return 'array';
508                     case RegExp: return 'regexp';
509                 }
510                 if(typeof o.length == 'number' && typeof o.item == 'function') {
511                     return 'nodelist';
512                 }
513             }
514             return t;
515         },
516
517         /**
518          * Returns true if the passed value is null, undefined or an empty string (optional).
519          * @param {Mixed} value The value to test
520          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
521          * @return {Boolean}
522          */
523         isEmpty : function(v, allowBlank){
524             return v === null || v === undefined || (!allowBlank ? v === '' : false);
525         },
526         
527         /** @type Boolean */
528         isOpera : isOpera,
529         /** @type Boolean */
530         isSafari : isSafari,
531         /** @type Boolean */
532         isIE : isIE,
533         /** @type Boolean */
534         isIE7 : isIE7,
535         /** @type Boolean */
536         isGecko : isGecko,
537         /** @type Boolean */
538         isBorderBox : isBorderBox,
539         /** @type Boolean */
540         isWindows : isWindows,
541         /** @type Boolean */
542         isLinux : isLinux,
543         /** @type Boolean */
544         isMac : isMac,
545
546         /**
547          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548          * you may want to set this to true.
549          * @type Boolean
550          */
551         useShims : ((isIE && !isIE7) || (isGecko && isMac))
552     });
553
554
555 })();
556
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
559 /*
560  * Based on:
561  * Ext JS Library 1.1.1
562  * Copyright(c) 2006-2007, Ext JS, LLC.
563  *
564  * Originally Released Under LGPL - original licence link has changed is not relivant.
565  *
566  * Fork - LGPL
567  * <script type="text/javascript">
568  */
569
570 (function() {    
571     // wrappedn so fnCleanup is not in global scope...
572     if(Roo.isIE) {
573         function fnCleanUp() {
574             var p = Function.prototype;
575             delete p.createSequence;
576             delete p.defer;
577             delete p.createDelegate;
578             delete p.createCallback;
579             delete p.createInterceptor;
580
581             window.detachEvent("onunload", fnCleanUp);
582         }
583         window.attachEvent("onunload", fnCleanUp);
584     }
585 })();
586
587
588 /**
589  * @class Function
590  * These functions are available on every Function object (any JavaScript function).
591  */
592 Roo.apply(Function.prototype, {
593      /**
594      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596      * Will create a function that is bound to those 2 args.
597      * @return {Function} The new function
598     */
599     createCallback : function(/*args...*/){
600         // make args available, in function below
601         var args = arguments;
602         var method = this;
603         return function() {
604             return method.apply(window, args);
605         };
606     },
607
608     /**
609      * Creates a delegate (callback) that sets the scope to obj.
610      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611      * Will create a function that is automatically scoped to this.
612      * @param {Object} obj (optional) The object for which the scope is set
613      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615      *                                             if a number the args are inserted at the specified position
616      * @return {Function} The new function
617      */
618     createDelegate : function(obj, args, appendArgs){
619         var method = this;
620         return function() {
621             var callArgs = args || arguments;
622             if(appendArgs === true){
623                 callArgs = Array.prototype.slice.call(arguments, 0);
624                 callArgs = callArgs.concat(args);
625             }else if(typeof appendArgs == "number"){
626                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
629             }
630             return method.apply(obj || window, callArgs);
631         };
632     },
633
634     /**
635      * Calls this function after the number of millseconds specified.
636      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637      * @param {Object} obj (optional) The object for which the scope is set
638      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640      *                                             if a number the args are inserted at the specified position
641      * @return {Number} The timeout id that can be used with clearTimeout
642      */
643     defer : function(millis, obj, args, appendArgs){
644         var fn = this.createDelegate(obj, args, appendArgs);
645         if(millis){
646             return setTimeout(fn, millis);
647         }
648         fn();
649         return 0;
650     },
651     /**
652      * Create a combined function call sequence of the original function + the passed function.
653      * The resulting function returns the results of the original function.
654      * The passed fcn is called with the parameters of the original function
655      * @param {Function} fcn The function to sequence
656      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657      * @return {Function} The new function
658      */
659     createSequence : function(fcn, scope){
660         if(typeof fcn != "function"){
661             return this;
662         }
663         var method = this;
664         return function() {
665             var retval = method.apply(this || window, arguments);
666             fcn.apply(scope || this || window, arguments);
667             return retval;
668         };
669     },
670
671     /**
672      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673      * The resulting function returns the results of the original function.
674      * The passed fcn is called with the parameters of the original function.
675      * @addon
676      * @param {Function} fcn The function to call before the original
677      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678      * @return {Function} The new function
679      */
680     createInterceptor : function(fcn, scope){
681         if(typeof fcn != "function"){
682             return this;
683         }
684         var method = this;
685         return function() {
686             fcn.target = this;
687             fcn.method = method;
688             if(fcn.apply(scope || this || window, arguments) === false){
689                 return;
690             }
691             return method.apply(this || window, arguments);
692         };
693     }
694 });
695 /*
696  * Based on:
697  * Ext JS Library 1.1.1
698  * Copyright(c) 2006-2007, Ext JS, LLC.
699  *
700  * Originally Released Under LGPL - original licence link has changed is not relivant.
701  *
702  * Fork - LGPL
703  * <script type="text/javascript">
704  */
705
706 Roo.applyIf(String, {
707     
708     /** @scope String */
709     
710     /**
711      * Escapes the passed string for ' and \
712      * @param {String} string The string to escape
713      * @return {String} The escaped string
714      * @static
715      */
716     escape : function(string) {
717         return string.replace(/('|\\)/g, "\\$1");
718     },
719
720     /**
721      * Pads the left side of a string with a specified character.  This is especially useful
722      * for normalizing number and date strings.  Example usage:
723      * <pre><code>
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
726 </code></pre>
727      * @param {String} string The original string
728      * @param {Number} size The total length of the output string
729      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730      * @return {String} The padded string
731      * @static
732      */
733     leftPad : function (val, size, ch) {
734         var result = new String(val);
735         if(ch === null || ch === undefined || ch === '') {
736             ch = " ";
737         }
738         while (result.length < size) {
739             result = ch + result;
740         }
741         return result;
742     },
743
744     /**
745      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
746      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
747      * <pre><code>
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
751 </code></pre>
752      * @param {String} string The tokenized string to be formatted
753      * @param {String} value1 The value to replace token {0}
754      * @param {String} value2 Etc...
755      * @return {String} The formatted string
756      * @static
757      */
758     format : function(format){
759         var args = Array.prototype.slice.call(arguments, 1);
760         return format.replace(/\{(\d+)\}/g, function(m, i){
761             return Roo.util.Format.htmlEncode(args[i]);
762         });
763     }
764 });
765
766 /**
767  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
768  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
769  * they are already different, the first value passed in is returned.  Note that this method returns the new value
770  * but does not change the current string.
771  * <pre><code>
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
774
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
777 </code></pre>
778  * @param {String} value The value to compare to the current string
779  * @param {String} other The new value to use if the string already equals the first value passed in
780  * @return {String} The new value
781  */
782  
783 String.prototype.toggle = function(value, other){
784     return this == value ? other : value;
785 };/*
786  * Based on:
787  * Ext JS Library 1.1.1
788  * Copyright(c) 2006-2007, Ext JS, LLC.
789  *
790  * Originally Released Under LGPL - original licence link has changed is not relivant.
791  *
792  * Fork - LGPL
793  * <script type="text/javascript">
794  */
795
796  /**
797  * @class Number
798  */
799 Roo.applyIf(Number.prototype, {
800     /**
801      * Checks whether or not the current number is within a desired range.  If the number is already within the
802      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803      * exceeded.  Note that this method returns the constrained value but does not change the current number.
804      * @param {Number} min The minimum number in the range
805      * @param {Number} max The maximum number in the range
806      * @return {Number} The constrained value if outside the range, otherwise the current value
807      */
808     constrain : function(min, max){
809         return Math.min(Math.max(this, min), max);
810     }
811 });/*
812  * Based on:
813  * Ext JS Library 1.1.1
814  * Copyright(c) 2006-2007, Ext JS, LLC.
815  *
816  * Originally Released Under LGPL - original licence link has changed is not relivant.
817  *
818  * Fork - LGPL
819  * <script type="text/javascript">
820  */
821  /**
822  * @class Array
823  */
824 Roo.applyIf(Array.prototype, {
825     /**
826      * Checks whether or not the specified object exists in the array.
827      * @param {Object} o The object to check for
828      * @return {Number} The index of o in the array (or -1 if it is not found)
829      */
830     indexOf : function(o){
831        for (var i = 0, len = this.length; i < len; i++){
832               if(this[i] == o) return i;
833        }
834            return -1;
835     },
836
837     /**
838      * Removes the specified object from the array.  If the object is not found nothing happens.
839      * @param {Object} o The object to remove
840      */
841     remove : function(o){
842        var index = this.indexOf(o);
843        if(index != -1){
844            this.splice(index, 1);
845        }
846     },
847     /**
848      * Map (JS 1.6 compatibility)
849      * @param {Function} function  to call
850      */
851     map : function(fun /*, thisp*/)
852     {
853         var len = this.length >>> 0;
854         if (typeof fun != "function")
855             throw new TypeError();
856
857         var res = new Array(len);
858         var thisp = arguments[1];
859         for (var i = 0; i < len; i++)
860         {
861             if (i in this)
862                 res[i] = fun.call(thisp, this[i], i, this);
863         }
864
865         return res;
866     }
867     
868 });
869
870
871
872 if (!Array.prototype.map)
873 {
874   Array.prototype.
875 }/*
876  * Based on:
877  * Ext JS Library 1.1.1
878  * Copyright(c) 2006-2007, Ext JS, LLC.
879  *
880  * Originally Released Under LGPL - original licence link has changed is not relivant.
881  *
882  * Fork - LGPL
883  * <script type="text/javascript">
884  */
885
886 /**
887  * @class Date
888  *
889  * The date parsing and format syntax is a subset of
890  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
891  * supported will provide results equivalent to their PHP versions.
892  *
893  * Following is the list of all currently supported formats:
894  *<pre>
895 Sample date:
896 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
897
898 Format  Output      Description
899 ------  ----------  --------------------------------------------------------------
900   d      10         Day of the month, 2 digits with leading zeros
901   D      Wed        A textual representation of a day, three letters
902   j      10         Day of the month without leading zeros
903   l      Wednesday  A full textual representation of the day of the week
904   S      th         English ordinal day of month suffix, 2 chars (use with j)
905   w      3          Numeric representation of the day of the week
906   z      9          The julian date, or day of the year (0-365)
907   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
908   F      January    A full textual representation of the month
909   m      01         Numeric representation of a month, with leading zeros
910   M      Jan        Month name abbreviation, three letters
911   n      1          Numeric representation of a month, without leading zeros
912   t      31         Number of days in the given month
913   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
914   Y      2007       A full numeric representation of a year, 4 digits
915   y      07         A two digit representation of a year
916   a      pm         Lowercase Ante meridiem and Post meridiem
917   A      PM         Uppercase Ante meridiem and Post meridiem
918   g      3          12-hour format of an hour without leading zeros
919   G      15         24-hour format of an hour without leading zeros
920   h      03         12-hour format of an hour with leading zeros
921   H      15         24-hour format of an hour with leading zeros
922   i      05         Minutes with leading zeros
923   s      01         Seconds, with leading zeros
924   O      -0600      Difference to Greenwich time (GMT) in hours
925   T      CST        Timezone setting of the machine running the code
926   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
927 </pre>
928  *
929  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
930  * <pre><code>
931 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
932 document.write(dt.format('Y-m-d'));                         //2007-01-10
933 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
934 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
935  </code></pre>
936  *
937  * Here are some standard date/time patterns that you might find helpful.  They
938  * are not part of the source of Date.js, but to use them you can simply copy this
939  * block of code into any script that is included after Date.js and they will also become
940  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
941  * <pre><code>
942 Date.patterns = {
943     ISO8601Long:"Y-m-d H:i:s",
944     ISO8601Short:"Y-m-d",
945     ShortDate: "n/j/Y",
946     LongDate: "l, F d, Y",
947     FullDateTime: "l, F d, Y g:i:s A",
948     MonthDay: "F d",
949     ShortTime: "g:i A",
950     LongTime: "g:i:s A",
951     SortableDateTime: "Y-m-d\\TH:i:s",
952     UniversalSortableDateTime: "Y-m-d H:i:sO",
953     YearMonth: "F, Y"
954 };
955 </code></pre>
956  *
957  * Example usage:
958  * <pre><code>
959 var dt = new Date();
960 document.write(dt.format(Date.patterns.ShortDate));
961  </code></pre>
962  */
963
964 /*
965  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
966  * They generate precompiled functions from date formats instead of parsing and
967  * processing the pattern every time you format a date.  These functions are available
968  * on every Date object (any javascript function).
969  *
970  * The original article and download are here:
971  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
972  *
973  */
974  
975  
976  // was in core
977 /**
978  Returns the number of milliseconds between this date and date
979  @param {Date} date (optional) Defaults to now
980  @return {Number} The diff in milliseconds
981  @member Date getElapsed
982  */
983 Date.prototype.getElapsed = function(date) {
984         return Math.abs((date || new Date()).getTime()-this.getTime());
985 };
986 // was in date file..
987
988
989 // private
990 Date.parseFunctions = {count:0};
991 // private
992 Date.parseRegexes = [];
993 // private
994 Date.formatFunctions = {count:0};
995
996 // private
997 Date.prototype.dateFormat = function(format) {
998     if (Date.formatFunctions[format] == null) {
999         Date.createNewFormat(format);
1000     }
1001     var func = Date.formatFunctions[format];
1002     return this[func]();
1003 };
1004
1005
1006 /**
1007  * Formats a date given the supplied format string
1008  * @param {String} format The format string
1009  * @return {String} The formatted date
1010  * @method
1011  */
1012 Date.prototype.format = Date.prototype.dateFormat;
1013
1014 // private
1015 Date.createNewFormat = function(format) {
1016     var funcName = "format" + Date.formatFunctions.count++;
1017     Date.formatFunctions[format] = funcName;
1018     var code = "Date.prototype." + funcName + " = function(){return ";
1019     var special = false;
1020     var ch = '';
1021     for (var i = 0; i < format.length; ++i) {
1022         ch = format.charAt(i);
1023         if (!special && ch == "\\") {
1024             special = true;
1025         }
1026         else if (special) {
1027             special = false;
1028             code += "'" + String.escape(ch) + "' + ";
1029         }
1030         else {
1031             code += Date.getFormatCode(ch);
1032         }
1033     }
1034     /** eval:var:zzzzzzzzzzzzz */
1035     eval(code.substring(0, code.length - 3) + ";}");
1036 };
1037
1038 // private
1039 Date.getFormatCode = function(character) {
1040     switch (character) {
1041     case "d":
1042         return "String.leftPad(this.getDate(), 2, '0') + ";
1043     case "D":
1044         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1045     case "j":
1046         return "this.getDate() + ";
1047     case "l":
1048         return "Date.dayNames[this.getDay()] + ";
1049     case "S":
1050         return "this.getSuffix() + ";
1051     case "w":
1052         return "this.getDay() + ";
1053     case "z":
1054         return "this.getDayOfYear() + ";
1055     case "W":
1056         return "this.getWeekOfYear() + ";
1057     case "F":
1058         return "Date.monthNames[this.getMonth()] + ";
1059     case "m":
1060         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1061     case "M":
1062         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1063     case "n":
1064         return "(this.getMonth() + 1) + ";
1065     case "t":
1066         return "this.getDaysInMonth() + ";
1067     case "L":
1068         return "(this.isLeapYear() ? 1 : 0) + ";
1069     case "Y":
1070         return "this.getFullYear() + ";
1071     case "y":
1072         return "('' + this.getFullYear()).substring(2, 4) + ";
1073     case "a":
1074         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1075     case "A":
1076         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1077     case "g":
1078         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1079     case "G":
1080         return "this.getHours() + ";
1081     case "h":
1082         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1083     case "H":
1084         return "String.leftPad(this.getHours(), 2, '0') + ";
1085     case "i":
1086         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1087     case "s":
1088         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1089     case "O":
1090         return "this.getGMTOffset() + ";
1091     case "T":
1092         return "this.getTimezone() + ";
1093     case "Z":
1094         return "(this.getTimezoneOffset() * -60) + ";
1095     default:
1096         return "'" + String.escape(character) + "' + ";
1097     }
1098 };
1099
1100 /**
1101  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1102  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1103  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1104  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1105  * string or the parse operation will fail.
1106  * Example Usage:
1107 <pre><code>
1108 //dt = Fri May 25 2007 (current date)
1109 var dt = new Date();
1110
1111 //dt = Thu May 25 2006 (today's month/day in 2006)
1112 dt = Date.parseDate("2006", "Y");
1113
1114 //dt = Sun Jan 15 2006 (all date parts specified)
1115 dt = Date.parseDate("2006-1-15", "Y-m-d");
1116
1117 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1118 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1119 </code></pre>
1120  * @param {String} input The unparsed date as a string
1121  * @param {String} format The format the date is in
1122  * @return {Date} The parsed date
1123  * @static
1124  */
1125 Date.parseDate = function(input, format) {
1126     if (Date.parseFunctions[format] == null) {
1127         Date.createParser(format);
1128     }
1129     var func = Date.parseFunctions[format];
1130     return Date[func](input);
1131 };
1132 /**
1133  * @private
1134  */
1135 Date.createParser = function(format) {
1136     var funcName = "parse" + Date.parseFunctions.count++;
1137     var regexNum = Date.parseRegexes.length;
1138     var currentGroup = 1;
1139     Date.parseFunctions[format] = funcName;
1140
1141     var code = "Date." + funcName + " = function(input){\n"
1142         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1143         + "var d = new Date();\n"
1144         + "y = d.getFullYear();\n"
1145         + "m = d.getMonth();\n"
1146         + "d = d.getDate();\n"
1147         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1148         + "if (results && results.length > 0) {";
1149     var regex = "";
1150
1151     var special = false;
1152     var ch = '';
1153     for (var i = 0; i < format.length; ++i) {
1154         ch = format.charAt(i);
1155         if (!special && ch == "\\") {
1156             special = true;
1157         }
1158         else if (special) {
1159             special = false;
1160             regex += String.escape(ch);
1161         }
1162         else {
1163             var obj = Date.formatCodeToRegex(ch, currentGroup);
1164             currentGroup += obj.g;
1165             regex += obj.s;
1166             if (obj.g && obj.c) {
1167                 code += obj.c;
1168             }
1169         }
1170     }
1171
1172     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1173         + "{v = new Date(y, m, d, h, i, s);}\n"
1174         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1175         + "{v = new Date(y, m, d, h, i);}\n"
1176         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1177         + "{v = new Date(y, m, d, h);}\n"
1178         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1179         + "{v = new Date(y, m, d);}\n"
1180         + "else if (y >= 0 && m >= 0)\n"
1181         + "{v = new Date(y, m);}\n"
1182         + "else if (y >= 0)\n"
1183         + "{v = new Date(y);}\n"
1184         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1185         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1186         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1187         + ";}";
1188
1189     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1190     /** eval:var:zzzzzzzzzzzzz */
1191     eval(code);
1192 };
1193
1194 // private
1195 Date.formatCodeToRegex = function(character, currentGroup) {
1196     switch (character) {
1197     case "D":
1198         return {g:0,
1199         c:null,
1200         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1201     case "j":
1202         return {g:1,
1203             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1204             s:"(\\d{1,2})"}; // day of month without leading zeroes
1205     case "d":
1206         return {g:1,
1207             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1208             s:"(\\d{2})"}; // day of month with leading zeroes
1209     case "l":
1210         return {g:0,
1211             c:null,
1212             s:"(?:" + Date.dayNames.join("|") + ")"};
1213     case "S":
1214         return {g:0,
1215             c:null,
1216             s:"(?:st|nd|rd|th)"};
1217     case "w":
1218         return {g:0,
1219             c:null,
1220             s:"\\d"};
1221     case "z":
1222         return {g:0,
1223             c:null,
1224             s:"(?:\\d{1,3})"};
1225     case "W":
1226         return {g:0,
1227             c:null,
1228             s:"(?:\\d{2})"};
1229     case "F":
1230         return {g:1,
1231             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1232             s:"(" + Date.monthNames.join("|") + ")"};
1233     case "M":
1234         return {g:1,
1235             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1236             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1237     case "n":
1238         return {g:1,
1239             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1240             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1241     case "m":
1242         return {g:1,
1243             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1244             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1245     case "t":
1246         return {g:0,
1247             c:null,
1248             s:"\\d{1,2}"};
1249     case "L":
1250         return {g:0,
1251             c:null,
1252             s:"(?:1|0)"};
1253     case "Y":
1254         return {g:1,
1255             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1256             s:"(\\d{4})"};
1257     case "y":
1258         return {g:1,
1259             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1260                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1261             s:"(\\d{1,2})"};
1262     case "a":
1263         return {g:1,
1264             c:"if (results[" + currentGroup + "] == 'am') {\n"
1265                 + "if (h == 12) { h = 0; }\n"
1266                 + "} else { if (h < 12) { h += 12; }}",
1267             s:"(am|pm)"};
1268     case "A":
1269         return {g:1,
1270             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1271                 + "if (h == 12) { h = 0; }\n"
1272                 + "} else { if (h < 12) { h += 12; }}",
1273             s:"(AM|PM)"};
1274     case "g":
1275     case "G":
1276         return {g:1,
1277             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1278             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1279     case "h":
1280     case "H":
1281         return {g:1,
1282             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1283             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1284     case "i":
1285         return {g:1,
1286             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1287             s:"(\\d{2})"};
1288     case "s":
1289         return {g:1,
1290             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1291             s:"(\\d{2})"};
1292     case "O":
1293         return {g:1,
1294             c:[
1295                 "o = results[", currentGroup, "];\n",
1296                 "var sn = o.substring(0,1);\n", // get + / - sign
1297                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1298                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1299                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1300                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1301             ].join(""),
1302             s:"([+\-]\\d{4})"};
1303     case "T":
1304         return {g:0,
1305             c:null,
1306             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1307     case "Z":
1308         return {g:1,
1309             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1310                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1311             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1312     default:
1313         return {g:0,
1314             c:null,
1315             s:String.escape(character)};
1316     }
1317 };
1318
1319 /**
1320  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1321  * @return {String} The abbreviated timezone name (e.g. 'CST')
1322  */
1323 Date.prototype.getTimezone = function() {
1324     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1325 };
1326
1327 /**
1328  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1329  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1330  */
1331 Date.prototype.getGMTOffset = function() {
1332     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1333         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1334         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1335 };
1336
1337 /**
1338  * Get the numeric day number of the year, adjusted for leap year.
1339  * @return {Number} 0 through 364 (365 in leap years)
1340  */
1341 Date.prototype.getDayOfYear = function() {
1342     var num = 0;
1343     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1344     for (var i = 0; i < this.getMonth(); ++i) {
1345         num += Date.daysInMonth[i];
1346     }
1347     return num + this.getDate() - 1;
1348 };
1349
1350 /**
1351  * Get the string representation of the numeric week number of the year
1352  * (equivalent to the format specifier 'W').
1353  * @return {String} '00' through '52'
1354  */
1355 Date.prototype.getWeekOfYear = function() {
1356     // Skip to Thursday of this week
1357     var now = this.getDayOfYear() + (4 - this.getDay());
1358     // Find the first Thursday of the year
1359     var jan1 = new Date(this.getFullYear(), 0, 1);
1360     var then = (7 - jan1.getDay() + 4);
1361     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1362 };
1363
1364 /**
1365  * Whether or not the current date is in a leap year.
1366  * @return {Boolean} True if the current date is in a leap year, else false
1367  */
1368 Date.prototype.isLeapYear = function() {
1369     var year = this.getFullYear();
1370     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1371 };
1372
1373 /**
1374  * Get the first day of the current month, adjusted for leap year.  The returned value
1375  * is the numeric day index within the week (0-6) which can be used in conjunction with
1376  * the {@link #monthNames} array to retrieve the textual day name.
1377  * Example:
1378  *<pre><code>
1379 var dt = new Date('1/10/2007');
1380 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1381 </code></pre>
1382  * @return {Number} The day number (0-6)
1383  */
1384 Date.prototype.getFirstDayOfMonth = function() {
1385     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1386     return (day < 0) ? (day + 7) : day;
1387 };
1388
1389 /**
1390  * Get the last day of the current month, adjusted for leap year.  The returned value
1391  * is the numeric day index within the week (0-6) which can be used in conjunction with
1392  * the {@link #monthNames} array to retrieve the textual day name.
1393  * Example:
1394  *<pre><code>
1395 var dt = new Date('1/10/2007');
1396 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1397 </code></pre>
1398  * @return {Number} The day number (0-6)
1399  */
1400 Date.prototype.getLastDayOfMonth = function() {
1401     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1402     return (day < 0) ? (day + 7) : day;
1403 };
1404
1405
1406 /**
1407  * Get the first date of this date's month
1408  * @return {Date}
1409  */
1410 Date.prototype.getFirstDateOfMonth = function() {
1411     return new Date(this.getFullYear(), this.getMonth(), 1);
1412 };
1413
1414 /**
1415  * Get the last date of this date's month
1416  * @return {Date}
1417  */
1418 Date.prototype.getLastDateOfMonth = function() {
1419     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1420 };
1421 /**
1422  * Get the number of days in the current month, adjusted for leap year.
1423  * @return {Number} The number of days in the month
1424  */
1425 Date.prototype.getDaysInMonth = function() {
1426     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1427     return Date.daysInMonth[this.getMonth()];
1428 };
1429
1430 /**
1431  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1432  * @return {String} 'st, 'nd', 'rd' or 'th'
1433  */
1434 Date.prototype.getSuffix = function() {
1435     switch (this.getDate()) {
1436         case 1:
1437         case 21:
1438         case 31:
1439             return "st";
1440         case 2:
1441         case 22:
1442             return "nd";
1443         case 3:
1444         case 23:
1445             return "rd";
1446         default:
1447             return "th";
1448     }
1449 };
1450
1451 // private
1452 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1453
1454 /**
1455  * An array of textual month names.
1456  * Override these values for international dates, for example...
1457  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1458  * @type Array
1459  * @static
1460  */
1461 Date.monthNames =
1462    ["January",
1463     "February",
1464     "March",
1465     "April",
1466     "May",
1467     "June",
1468     "July",
1469     "August",
1470     "September",
1471     "October",
1472     "November",
1473     "December"];
1474
1475 /**
1476  * An array of textual day names.
1477  * Override these values for international dates, for example...
1478  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1479  * @type Array
1480  * @static
1481  */
1482 Date.dayNames =
1483    ["Sunday",
1484     "Monday",
1485     "Tuesday",
1486     "Wednesday",
1487     "Thursday",
1488     "Friday",
1489     "Saturday"];
1490
1491 // private
1492 Date.y2kYear = 50;
1493 // private
1494 Date.monthNumbers = {
1495     Jan:0,
1496     Feb:1,
1497     Mar:2,
1498     Apr:3,
1499     May:4,
1500     Jun:5,
1501     Jul:6,
1502     Aug:7,
1503     Sep:8,
1504     Oct:9,
1505     Nov:10,
1506     Dec:11};
1507
1508 /**
1509  * Creates and returns a new Date instance with the exact same date value as the called instance.
1510  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1511  * variable will also be changed.  When the intention is to create a new variable that will not
1512  * modify the original instance, you should create a clone.
1513  *
1514  * Example of correctly cloning a date:
1515  * <pre><code>
1516 //wrong way:
1517 var orig = new Date('10/1/2006');
1518 var copy = orig;
1519 copy.setDate(5);
1520 document.write(orig);  //returns 'Thu Oct 05 2006'!
1521
1522 //correct way:
1523 var orig = new Date('10/1/2006');
1524 var copy = orig.clone();
1525 copy.setDate(5);
1526 document.write(orig);  //returns 'Thu Oct 01 2006'
1527 </code></pre>
1528  * @return {Date} The new Date instance
1529  */
1530 Date.prototype.clone = function() {
1531         return new Date(this.getTime());
1532 };
1533
1534 /**
1535  * Clears any time information from this date
1536  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1537  @return {Date} this or the clone
1538  */
1539 Date.prototype.clearTime = function(clone){
1540     if(clone){
1541         return this.clone().clearTime();
1542     }
1543     this.setHours(0);
1544     this.setMinutes(0);
1545     this.setSeconds(0);
1546     this.setMilliseconds(0);
1547     return this;
1548 };
1549
1550 // private
1551 // safari setMonth is broken
1552 if(Roo.isSafari){
1553     Date.brokenSetMonth = Date.prototype.setMonth;
1554         Date.prototype.setMonth = function(num){
1555                 if(num <= -1){
1556                         var n = Math.ceil(-num);
1557                         var back_year = Math.ceil(n/12);
1558                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1559                         this.setFullYear(this.getFullYear() - back_year);
1560                         return Date.brokenSetMonth.call(this, month);
1561                 } else {
1562                         return Date.brokenSetMonth.apply(this, arguments);
1563                 }
1564         };
1565 }
1566
1567 /** Date interval constant 
1568 * @static 
1569 * @type String */
1570 Date.MILLI = "ms";
1571 /** Date interval constant 
1572 * @static 
1573 * @type String */
1574 Date.SECOND = "s";
1575 /** Date interval constant 
1576 * @static 
1577 * @type String */
1578 Date.MINUTE = "mi";
1579 /** Date interval constant 
1580 * @static 
1581 * @type String */
1582 Date.HOUR = "h";
1583 /** Date interval constant 
1584 * @static 
1585 * @type String */
1586 Date.DAY = "d";
1587 /** Date interval constant 
1588 * @static 
1589 * @type String */
1590 Date.MONTH = "mo";
1591 /** Date interval constant 
1592 * @static 
1593 * @type String */
1594 Date.YEAR = "y";
1595
1596 /**
1597  * Provides a convenient method of performing basic date arithmetic.  This method
1598  * does not modify the Date instance being called - it creates and returns
1599  * a new Date instance containing the resulting date value.
1600  *
1601  * Examples:
1602  * <pre><code>
1603 //Basic usage:
1604 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1605 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1606
1607 //Negative values will subtract correctly:
1608 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1609 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1610
1611 //You can even chain several calls together in one line!
1612 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1613 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1614  </code></pre>
1615  *
1616  * @param {String} interval   A valid date interval enum value
1617  * @param {Number} value      The amount to add to the current date
1618  * @return {Date} The new Date instance
1619  */
1620 Date.prototype.add = function(interval, value){
1621   var d = this.clone();
1622   if (!interval || value === 0) return d;
1623   switch(interval.toLowerCase()){
1624     case Date.MILLI:
1625       d.setMilliseconds(this.getMilliseconds() + value);
1626       break;
1627     case Date.SECOND:
1628       d.setSeconds(this.getSeconds() + value);
1629       break;
1630     case Date.MINUTE:
1631       d.setMinutes(this.getMinutes() + value);
1632       break;
1633     case Date.HOUR:
1634       d.setHours(this.getHours() + value);
1635       break;
1636     case Date.DAY:
1637       d.setDate(this.getDate() + value);
1638       break;
1639     case Date.MONTH:
1640       var day = this.getDate();
1641       if(day > 28){
1642           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1643       }
1644       d.setDate(day);
1645       d.setMonth(this.getMonth() + value);
1646       break;
1647     case Date.YEAR:
1648       d.setFullYear(this.getFullYear() + value);
1649       break;
1650   }
1651   return d;
1652 };/*
1653  * Based on:
1654  * Ext JS Library 1.1.1
1655  * Copyright(c) 2006-2007, Ext JS, LLC.
1656  *
1657  * Originally Released Under LGPL - original licence link has changed is not relivant.
1658  *
1659  * Fork - LGPL
1660  * <script type="text/javascript">
1661  */
1662
1663 Roo.lib.Dom = {
1664     getViewWidth : function(full) {
1665         return full ? this.getDocumentWidth() : this.getViewportWidth();
1666     },
1667
1668     getViewHeight : function(full) {
1669         return full ? this.getDocumentHeight() : this.getViewportHeight();
1670     },
1671
1672     getDocumentHeight: function() {
1673         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1674         return Math.max(scrollHeight, this.getViewportHeight());
1675     },
1676
1677     getDocumentWidth: function() {
1678         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1679         return Math.max(scrollWidth, this.getViewportWidth());
1680     },
1681
1682     getViewportHeight: function() {
1683         var height = self.innerHeight;
1684         var mode = document.compatMode;
1685
1686         if ((mode || Roo.isIE) && !Roo.isOpera) {
1687             height = (mode == "CSS1Compat") ?
1688                      document.documentElement.clientHeight :
1689                      document.body.clientHeight;
1690         }
1691
1692         return height;
1693     },
1694
1695     getViewportWidth: function() {
1696         var width = self.innerWidth;
1697         var mode = document.compatMode;
1698
1699         if (mode || Roo.isIE) {
1700             width = (mode == "CSS1Compat") ?
1701                     document.documentElement.clientWidth :
1702                     document.body.clientWidth;
1703         }
1704         return width;
1705     },
1706
1707     isAncestor : function(p, c) {
1708         p = Roo.getDom(p);
1709         c = Roo.getDom(c);
1710         if (!p || !c) {
1711             return false;
1712         }
1713
1714         if (p.contains && !Roo.isSafari) {
1715             return p.contains(c);
1716         } else if (p.compareDocumentPosition) {
1717             return !!(p.compareDocumentPosition(c) & 16);
1718         } else {
1719             var parent = c.parentNode;
1720             while (parent) {
1721                 if (parent == p) {
1722                     return true;
1723                 }
1724                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1725                     return false;
1726                 }
1727                 parent = parent.parentNode;
1728             }
1729             return false;
1730         }
1731     },
1732
1733     getRegion : function(el) {
1734         return Roo.lib.Region.getRegion(el);
1735     },
1736
1737     getY : function(el) {
1738         return this.getXY(el)[1];
1739     },
1740
1741     getX : function(el) {
1742         return this.getXY(el)[0];
1743     },
1744
1745     getXY : function(el) {
1746         var p, pe, b, scroll, bd = document.body;
1747         el = Roo.getDom(el);
1748         var fly = Roo.lib.AnimBase.fly;
1749         if (el.getBoundingClientRect) {
1750             b = el.getBoundingClientRect();
1751             scroll = fly(document).getScroll();
1752             return [b.left + scroll.left, b.top + scroll.top];
1753         }
1754         var x = 0, y = 0;
1755
1756         p = el;
1757
1758         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1759
1760         while (p) {
1761
1762             x += p.offsetLeft;
1763             y += p.offsetTop;
1764
1765             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1766                 hasAbsolute = true;
1767             }
1768
1769             if (Roo.isGecko) {
1770                 pe = fly(p);
1771
1772                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1773                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1774
1775
1776                 x += bl;
1777                 y += bt;
1778
1779
1780                 if (p != el && pe.getStyle('overflow') != 'visible') {
1781                     x += bl;
1782                     y += bt;
1783                 }
1784             }
1785             p = p.offsetParent;
1786         }
1787
1788         if (Roo.isSafari && hasAbsolute) {
1789             x -= bd.offsetLeft;
1790             y -= bd.offsetTop;
1791         }
1792
1793         if (Roo.isGecko && !hasAbsolute) {
1794             var dbd = fly(bd);
1795             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1796             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1797         }
1798
1799         p = el.parentNode;
1800         while (p && p != bd) {
1801             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1802                 x -= p.scrollLeft;
1803                 y -= p.scrollTop;
1804             }
1805             p = p.parentNode;
1806         }
1807         return [x, y];
1808     },
1809  
1810   
1811
1812
1813     setXY : function(el, xy) {
1814         el = Roo.fly(el, '_setXY');
1815         el.position();
1816         var pts = el.translatePoints(xy);
1817         if (xy[0] !== false) {
1818             el.dom.style.left = pts.left + "px";
1819         }
1820         if (xy[1] !== false) {
1821             el.dom.style.top = pts.top + "px";
1822         }
1823     },
1824
1825     setX : function(el, x) {
1826         this.setXY(el, [x, false]);
1827     },
1828
1829     setY : function(el, y) {
1830         this.setXY(el, [false, y]);
1831     }
1832 };
1833 /*
1834  * Portions of this file are based on pieces of Yahoo User Interface Library
1835  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1836  * YUI licensed under the BSD License:
1837  * http://developer.yahoo.net/yui/license.txt
1838  * <script type="text/javascript">
1839  *
1840  */
1841
1842 Roo.lib.Event = function() {
1843     var loadComplete = false;
1844     var listeners = [];
1845     var unloadListeners = [];
1846     var retryCount = 0;
1847     var onAvailStack = [];
1848     var counter = 0;
1849     var lastError = null;
1850
1851     return {
1852         POLL_RETRYS: 200,
1853         POLL_INTERVAL: 20,
1854         EL: 0,
1855         TYPE: 1,
1856         FN: 2,
1857         WFN: 3,
1858         OBJ: 3,
1859         ADJ_SCOPE: 4,
1860         _interval: null,
1861
1862         startInterval: function() {
1863             if (!this._interval) {
1864                 var self = this;
1865                 var callback = function() {
1866                     self._tryPreloadAttach();
1867                 };
1868                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1869
1870             }
1871         },
1872
1873         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1874             onAvailStack.push({ id:         p_id,
1875                 fn:         p_fn,
1876                 obj:        p_obj,
1877                 override:   p_override,
1878                 checkReady: false    });
1879
1880             retryCount = this.POLL_RETRYS;
1881             this.startInterval();
1882         },
1883
1884
1885         addListener: function(el, eventName, fn) {
1886             el = Roo.getDom(el);
1887             if (!el || !fn) {
1888                 return false;
1889             }
1890
1891             if ("unload" == eventName) {
1892                 unloadListeners[unloadListeners.length] =
1893                 [el, eventName, fn];
1894                 return true;
1895             }
1896
1897             var wrappedFn = function(e) {
1898                 return fn(Roo.lib.Event.getEvent(e));
1899             };
1900
1901             var li = [el, eventName, fn, wrappedFn];
1902
1903             var index = listeners.length;
1904             listeners[index] = li;
1905
1906             this.doAdd(el, eventName, wrappedFn, false);
1907             return true;
1908
1909         },
1910
1911
1912         removeListener: function(el, eventName, fn) {
1913             var i, len;
1914
1915             el = Roo.getDom(el);
1916
1917             if(!fn) {
1918                 return this.purgeElement(el, false, eventName);
1919             }
1920
1921
1922             if ("unload" == eventName) {
1923
1924                 for (i = 0,len = unloadListeners.length; i < len; i++) {
1925                     var li = unloadListeners[i];
1926                     if (li &&
1927                         li[0] == el &&
1928                         li[1] == eventName &&
1929                         li[2] == fn) {
1930                         unloadListeners.splice(i, 1);
1931                         return true;
1932                     }
1933                 }
1934
1935                 return false;
1936             }
1937
1938             var cacheItem = null;
1939
1940
1941             var index = arguments[3];
1942
1943             if ("undefined" == typeof index) {
1944                 index = this._getCacheIndex(el, eventName, fn);
1945             }
1946
1947             if (index >= 0) {
1948                 cacheItem = listeners[index];
1949             }
1950
1951             if (!el || !cacheItem) {
1952                 return false;
1953             }
1954
1955             this.doRemove(el, eventName, cacheItem[this.WFN], false);
1956
1957             delete listeners[index][this.WFN];
1958             delete listeners[index][this.FN];
1959             listeners.splice(index, 1);
1960
1961             return true;
1962
1963         },
1964
1965
1966         getTarget: function(ev, resolveTextNode) {
1967             ev = ev.browserEvent || ev;
1968             var t = ev.target || ev.srcElement;
1969             return this.resolveTextNode(t);
1970         },
1971
1972
1973         resolveTextNode: function(node) {
1974             if (Roo.isSafari && node && 3 == node.nodeType) {
1975                 return node.parentNode;
1976             } else {
1977                 return node;
1978             }
1979         },
1980
1981
1982         getPageX: function(ev) {
1983             ev = ev.browserEvent || ev;
1984             var x = ev.pageX;
1985             if (!x && 0 !== x) {
1986                 x = ev.clientX || 0;
1987
1988                 if (Roo.isIE) {
1989                     x += this.getScroll()[1];
1990                 }
1991             }
1992
1993             return x;
1994         },
1995
1996
1997         getPageY: function(ev) {
1998             ev = ev.browserEvent || ev;
1999             var y = ev.pageY;
2000             if (!y && 0 !== y) {
2001                 y = ev.clientY || 0;
2002
2003                 if (Roo.isIE) {
2004                     y += this.getScroll()[0];
2005                 }
2006             }
2007
2008
2009             return y;
2010         },
2011
2012
2013         getXY: function(ev) {
2014             ev = ev.browserEvent || ev;
2015             return [this.getPageX(ev), this.getPageY(ev)];
2016         },
2017
2018
2019         getRelatedTarget: function(ev) {
2020             ev = ev.browserEvent || ev;
2021             var t = ev.relatedTarget;
2022             if (!t) {
2023                 if (ev.type == "mouseout") {
2024                     t = ev.toElement;
2025                 } else if (ev.type == "mouseover") {
2026                     t = ev.fromElement;
2027                 }
2028             }
2029
2030             return this.resolveTextNode(t);
2031         },
2032
2033
2034         getTime: function(ev) {
2035             ev = ev.browserEvent || ev;
2036             if (!ev.time) {
2037                 var t = new Date().getTime();
2038                 try {
2039                     ev.time = t;
2040                 } catch(ex) {
2041                     this.lastError = ex;
2042                     return t;
2043                 }
2044             }
2045
2046             return ev.time;
2047         },
2048
2049
2050         stopEvent: function(ev) {
2051             this.stopPropagation(ev);
2052             this.preventDefault(ev);
2053         },
2054
2055
2056         stopPropagation: function(ev) {
2057             ev = ev.browserEvent || ev;
2058             if (ev.stopPropagation) {
2059                 ev.stopPropagation();
2060             } else {
2061                 ev.cancelBubble = true;
2062             }
2063         },
2064
2065
2066         preventDefault: function(ev) {
2067             ev = ev.browserEvent || ev;
2068             if(ev.preventDefault) {
2069                 ev.preventDefault();
2070             } else {
2071                 ev.returnValue = false;
2072             }
2073         },
2074
2075
2076         getEvent: function(e) {
2077             var ev = e || window.event;
2078             if (!ev) {
2079                 var c = this.getEvent.caller;
2080                 while (c) {
2081                     ev = c.arguments[0];
2082                     if (ev && Event == ev.constructor) {
2083                         break;
2084                     }
2085                     c = c.caller;
2086                 }
2087             }
2088             return ev;
2089         },
2090
2091
2092         getCharCode: function(ev) {
2093             ev = ev.browserEvent || ev;
2094             return ev.charCode || ev.keyCode || 0;
2095         },
2096
2097
2098         _getCacheIndex: function(el, eventName, fn) {
2099             for (var i = 0,len = listeners.length; i < len; ++i) {
2100                 var li = listeners[i];
2101                 if (li &&
2102                     li[this.FN] == fn &&
2103                     li[this.EL] == el &&
2104                     li[this.TYPE] == eventName) {
2105                     return i;
2106                 }
2107             }
2108
2109             return -1;
2110         },
2111
2112
2113         elCache: {},
2114
2115
2116         getEl: function(id) {
2117             return document.getElementById(id);
2118         },
2119
2120
2121         clearCache: function() {
2122         },
2123
2124
2125         _load: function(e) {
2126             loadComplete = true;
2127             var EU = Roo.lib.Event;
2128
2129
2130             if (Roo.isIE) {
2131                 EU.doRemove(window, "load", EU._load);
2132             }
2133         },
2134
2135
2136         _tryPreloadAttach: function() {
2137
2138             if (this.locked) {
2139                 return false;
2140             }
2141
2142             this.locked = true;
2143
2144
2145             var tryAgain = !loadComplete;
2146             if (!tryAgain) {
2147                 tryAgain = (retryCount > 0);
2148             }
2149
2150
2151             var notAvail = [];
2152             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2153                 var item = onAvailStack[i];
2154                 if (item) {
2155                     var el = this.getEl(item.id);
2156
2157                     if (el) {
2158                         if (!item.checkReady ||
2159                             loadComplete ||
2160                             el.nextSibling ||
2161                             (document && document.body)) {
2162
2163                             var scope = el;
2164                             if (item.override) {
2165                                 if (item.override === true) {
2166                                     scope = item.obj;
2167                                 } else {
2168                                     scope = item.override;
2169                                 }
2170                             }
2171                             item.fn.call(scope, item.obj);
2172                             onAvailStack[i] = null;
2173                         }
2174                     } else {
2175                         notAvail.push(item);
2176                     }
2177                 }
2178             }
2179
2180             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2181
2182             if (tryAgain) {
2183
2184                 this.startInterval();
2185             } else {
2186                 clearInterval(this._interval);
2187                 this._interval = null;
2188             }
2189
2190             this.locked = false;
2191
2192             return true;
2193
2194         },
2195
2196
2197         purgeElement: function(el, recurse, eventName) {
2198             var elListeners = this.getListeners(el, eventName);
2199             if (elListeners) {
2200                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2201                     var l = elListeners[i];
2202                     this.removeListener(el, l.type, l.fn);
2203                 }
2204             }
2205
2206             if (recurse && el && el.childNodes) {
2207                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2208                     this.purgeElement(el.childNodes[i], recurse, eventName);
2209                 }
2210             }
2211         },
2212
2213
2214         getListeners: function(el, eventName) {
2215             var results = [], searchLists;
2216             if (!eventName) {
2217                 searchLists = [listeners, unloadListeners];
2218             } else if (eventName == "unload") {
2219                 searchLists = [unloadListeners];
2220             } else {
2221                 searchLists = [listeners];
2222             }
2223
2224             for (var j = 0; j < searchLists.length; ++j) {
2225                 var searchList = searchLists[j];
2226                 if (searchList && searchList.length > 0) {
2227                     for (var i = 0,len = searchList.length; i < len; ++i) {
2228                         var l = searchList[i];
2229                         if (l && l[this.EL] === el &&
2230                             (!eventName || eventName === l[this.TYPE])) {
2231                             results.push({
2232                                 type:   l[this.TYPE],
2233                                 fn:     l[this.FN],
2234                                 obj:    l[this.OBJ],
2235                                 adjust: l[this.ADJ_SCOPE],
2236                                 index:  i
2237                             });
2238                         }
2239                     }
2240                 }
2241             }
2242
2243             return (results.length) ? results : null;
2244         },
2245
2246
2247         _unload: function(e) {
2248
2249             var EU = Roo.lib.Event, i, j, l, len, index;
2250
2251             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2252                 l = unloadListeners[i];
2253                 if (l) {
2254                     var scope = window;
2255                     if (l[EU.ADJ_SCOPE]) {
2256                         if (l[EU.ADJ_SCOPE] === true) {
2257                             scope = l[EU.OBJ];
2258                         } else {
2259                             scope = l[EU.ADJ_SCOPE];
2260                         }
2261                     }
2262                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2263                     unloadListeners[i] = null;
2264                     l = null;
2265                     scope = null;
2266                 }
2267             }
2268
2269             unloadListeners = null;
2270
2271             if (listeners && listeners.length > 0) {
2272                 j = listeners.length;
2273                 while (j) {
2274                     index = j - 1;
2275                     l = listeners[index];
2276                     if (l) {
2277                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2278                                 l[EU.FN], index);
2279                     }
2280                     j = j - 1;
2281                 }
2282                 l = null;
2283
2284                 EU.clearCache();
2285             }
2286
2287             EU.doRemove(window, "unload", EU._unload);
2288
2289         },
2290
2291
2292         getScroll: function() {
2293             var dd = document.documentElement, db = document.body;
2294             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2295                 return [dd.scrollTop, dd.scrollLeft];
2296             } else if (db) {
2297                 return [db.scrollTop, db.scrollLeft];
2298             } else {
2299                 return [0, 0];
2300             }
2301         },
2302
2303
2304         doAdd: function () {
2305             if (window.addEventListener) {
2306                 return function(el, eventName, fn, capture) {
2307                     el.addEventListener(eventName, fn, (capture));
2308                 };
2309             } else if (window.attachEvent) {
2310                 return function(el, eventName, fn, capture) {
2311                     el.attachEvent("on" + eventName, fn);
2312                 };
2313             } else {
2314                 return function() {
2315                 };
2316             }
2317         }(),
2318
2319
2320         doRemove: function() {
2321             if (window.removeEventListener) {
2322                 return function (el, eventName, fn, capture) {
2323                     el.removeEventListener(eventName, fn, (capture));
2324                 };
2325             } else if (window.detachEvent) {
2326                 return function (el, eventName, fn) {
2327                     el.detachEvent("on" + eventName, fn);
2328                 };
2329             } else {
2330                 return function() {
2331                 };
2332             }
2333         }()
2334     };
2335     
2336 }();
2337 (function() {     
2338    
2339     var E = Roo.lib.Event;
2340     E.on = E.addListener;
2341     E.un = E.removeListener;
2342
2343     if (document && document.body) {
2344         E._load();
2345     } else {
2346         E.doAdd(window, "load", E._load);
2347     }
2348     E.doAdd(window, "unload", E._unload);
2349     E._tryPreloadAttach();
2350 })();
2351
2352 /*
2353  * Portions of this file are based on pieces of Yahoo User Interface Library
2354  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2355  * YUI licensed under the BSD License:
2356  * http://developer.yahoo.net/yui/license.txt
2357  * <script type="text/javascript">
2358  *
2359  */
2360
2361 (function() {
2362     
2363     Roo.lib.Ajax = {
2364         request : function(method, uri, cb, data, options) {
2365             if(options){
2366                 var hs = options.headers;
2367                 if(hs){
2368                     for(var h in hs){
2369                         if(hs.hasOwnProperty(h)){
2370                             this.initHeader(h, hs[h], false);
2371                         }
2372                     }
2373                 }
2374                 if(options.xmlData){
2375                     this.initHeader('Content-Type', 'text/xml', false);
2376                     method = 'POST';
2377                     data = options.xmlData;
2378                 }
2379             }
2380
2381             return this.asyncRequest(method, uri, cb, data);
2382         },
2383
2384         serializeForm : function(form) {
2385             if(typeof form == 'string') {
2386                 form = (document.getElementById(form) || document.forms[form]);
2387             }
2388
2389             var el, name, val, disabled, data = '', hasSubmit = false;
2390             for (var i = 0; i < form.elements.length; i++) {
2391                 el = form.elements[i];
2392                 disabled = form.elements[i].disabled;
2393                 name = form.elements[i].name;
2394                 val = form.elements[i].value;
2395
2396                 if (!disabled && name){
2397                     switch (el.type)
2398                             {
2399                         case 'select-one':
2400                         case 'select-multiple':
2401                             for (var j = 0; j < el.options.length; j++) {
2402                                 if (el.options[j].selected) {
2403                                     if (Roo.isIE) {
2404                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2405                                     }
2406                                     else {
2407                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2408                                     }
2409                                 }
2410                             }
2411                             break;
2412                         case 'radio':
2413                         case 'checkbox':
2414                             if (el.checked) {
2415                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2416                             }
2417                             break;
2418                         case 'file':
2419
2420                         case undefined:
2421
2422                         case 'reset':
2423
2424                         case 'button':
2425
2426                             break;
2427                         case 'submit':
2428                             if(hasSubmit == false) {
2429                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2430                                 hasSubmit = true;
2431                             }
2432                             break;
2433                         default:
2434                             data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2435                             break;
2436                     }
2437                 }
2438             }
2439             data = data.substr(0, data.length - 1);
2440             return data;
2441         },
2442
2443         headers:{},
2444
2445         hasHeaders:false,
2446
2447         useDefaultHeader:true,
2448
2449         defaultPostHeader:'application/x-www-form-urlencoded',
2450
2451         useDefaultXhrHeader:true,
2452
2453         defaultXhrHeader:'XMLHttpRequest',
2454
2455         hasDefaultHeaders:true,
2456
2457         defaultHeaders:{},
2458
2459         poll:{},
2460
2461         timeout:{},
2462
2463         pollInterval:50,
2464
2465         transactionId:0,
2466
2467         setProgId:function(id)
2468         {
2469             this.activeX.unshift(id);
2470         },
2471
2472         setDefaultPostHeader:function(b)
2473         {
2474             this.useDefaultHeader = b;
2475         },
2476
2477         setDefaultXhrHeader:function(b)
2478         {
2479             this.useDefaultXhrHeader = b;
2480         },
2481
2482         setPollingInterval:function(i)
2483         {
2484             if (typeof i == 'number' && isFinite(i)) {
2485                 this.pollInterval = i;
2486             }
2487         },
2488
2489         createXhrObject:function(transactionId)
2490         {
2491             var obj,http;
2492             try
2493             {
2494
2495                 http = new XMLHttpRequest();
2496
2497                 obj = { conn:http, tId:transactionId };
2498             }
2499             catch(e)
2500             {
2501                 for (var i = 0; i < this.activeX.length; ++i) {
2502                     try
2503                     {
2504
2505                         http = new ActiveXObject(this.activeX[i]);
2506
2507                         obj = { conn:http, tId:transactionId };
2508                         break;
2509                     }
2510                     catch(e) {
2511                     }
2512                 }
2513             }
2514             finally
2515             {
2516                 return obj;
2517             }
2518         },
2519
2520         getConnectionObject:function()
2521         {
2522             var o;
2523             var tId = this.transactionId;
2524
2525             try
2526             {
2527                 o = this.createXhrObject(tId);
2528                 if (o) {
2529                     this.transactionId++;
2530                 }
2531             }
2532             catch(e) {
2533             }
2534             finally
2535             {
2536                 return o;
2537             }
2538         },
2539
2540         asyncRequest:function(method, uri, callback, postData)
2541         {
2542             var o = this.getConnectionObject();
2543
2544             if (!o) {
2545                 return null;
2546             }
2547             else {
2548                 o.conn.open(method, uri, true);
2549
2550                 if (this.useDefaultXhrHeader) {
2551                     if (!this.defaultHeaders['X-Requested-With']) {
2552                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2553                     }
2554                 }
2555
2556                 if(postData && this.useDefaultHeader){
2557                     this.initHeader('Content-Type', this.defaultPostHeader);
2558                 }
2559
2560                  if (this.hasDefaultHeaders || this.hasHeaders) {
2561                     this.setHeader(o);
2562                 }
2563
2564                 this.handleReadyState(o, callback);
2565                 o.conn.send(postData || null);
2566
2567                 return o;
2568             }
2569         },
2570
2571         handleReadyState:function(o, callback)
2572         {
2573             var oConn = this;
2574
2575             if (callback && callback.timeout) {
2576                 this.timeout[o.tId] = window.setTimeout(function() {
2577                     oConn.abort(o, callback, true);
2578                 }, callback.timeout);
2579             }
2580
2581             this.poll[o.tId] = window.setInterval(
2582                     function() {
2583                         if (o.conn && o.conn.readyState == 4) {
2584                             window.clearInterval(oConn.poll[o.tId]);
2585                             delete oConn.poll[o.tId];
2586
2587                             if(callback && callback.timeout) {
2588                                 window.clearTimeout(oConn.timeout[o.tId]);
2589                                 delete oConn.timeout[o.tId];
2590                             }
2591
2592                             oConn.handleTransactionResponse(o, callback);
2593                         }
2594                     }
2595                     , this.pollInterval);
2596         },
2597
2598         handleTransactionResponse:function(o, callback, isAbort)
2599         {
2600
2601             if (!callback) {
2602                 this.releaseObject(o);
2603                 return;
2604             }
2605
2606             var httpStatus, responseObject;
2607
2608             try
2609             {
2610                 if (o.conn.status !== undefined && o.conn.status != 0) {
2611                     httpStatus = o.conn.status;
2612                 }
2613                 else {
2614                     httpStatus = 13030;
2615                 }
2616             }
2617             catch(e) {
2618
2619
2620                 httpStatus = 13030;
2621             }
2622
2623             if (httpStatus >= 200 && httpStatus < 300) {
2624                 responseObject = this.createResponseObject(o, callback.argument);
2625                 if (callback.success) {
2626                     if (!callback.scope) {
2627                         callback.success(responseObject);
2628                     }
2629                     else {
2630
2631
2632                         callback.success.apply(callback.scope, [responseObject]);
2633                     }
2634                 }
2635             }
2636             else {
2637                 switch (httpStatus) {
2638
2639                     case 12002:
2640                     case 12029:
2641                     case 12030:
2642                     case 12031:
2643                     case 12152:
2644                     case 13030:
2645                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2646                         if (callback.failure) {
2647                             if (!callback.scope) {
2648                                 callback.failure(responseObject);
2649                             }
2650                             else {
2651                                 callback.failure.apply(callback.scope, [responseObject]);
2652                             }
2653                         }
2654                         break;
2655                     default:
2656                         responseObject = this.createResponseObject(o, callback.argument);
2657                         if (callback.failure) {
2658                             if (!callback.scope) {
2659                                 callback.failure(responseObject);
2660                             }
2661                             else {
2662                                 callback.failure.apply(callback.scope, [responseObject]);
2663                             }
2664                         }
2665                 }
2666             }
2667
2668             this.releaseObject(o);
2669             responseObject = null;
2670         },
2671
2672         createResponseObject:function(o, callbackArg)
2673         {
2674             var obj = {};
2675             var headerObj = {};
2676
2677             try
2678             {
2679                 var headerStr = o.conn.getAllResponseHeaders();
2680                 var header = headerStr.split('\n');
2681                 for (var i = 0; i < header.length; i++) {
2682                     var delimitPos = header[i].indexOf(':');
2683                     if (delimitPos != -1) {
2684                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2685                     }
2686                 }
2687             }
2688             catch(e) {
2689             }
2690
2691             obj.tId = o.tId;
2692             obj.status = o.conn.status;
2693             obj.statusText = o.conn.statusText;
2694             obj.getResponseHeader = headerObj;
2695             obj.getAllResponseHeaders = headerStr;
2696             obj.responseText = o.conn.responseText;
2697             obj.responseXML = o.conn.responseXML;
2698
2699             if (typeof callbackArg !== undefined) {
2700                 obj.argument = callbackArg;
2701             }
2702
2703             return obj;
2704         },
2705
2706         createExceptionObject:function(tId, callbackArg, isAbort)
2707         {
2708             var COMM_CODE = 0;
2709             var COMM_ERROR = 'communication failure';
2710             var ABORT_CODE = -1;
2711             var ABORT_ERROR = 'transaction aborted';
2712
2713             var obj = {};
2714
2715             obj.tId = tId;
2716             if (isAbort) {
2717                 obj.status = ABORT_CODE;
2718                 obj.statusText = ABORT_ERROR;
2719             }
2720             else {
2721                 obj.status = COMM_CODE;
2722                 obj.statusText = COMM_ERROR;
2723             }
2724
2725             if (callbackArg) {
2726                 obj.argument = callbackArg;
2727             }
2728
2729             return obj;
2730         },
2731
2732         initHeader:function(label, value, isDefault)
2733         {
2734             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2735
2736             if (headerObj[label] === undefined) {
2737                 headerObj[label] = value;
2738             }
2739             else {
2740
2741
2742                 headerObj[label] = value + "," + headerObj[label];
2743             }
2744
2745             if (isDefault) {
2746                 this.hasDefaultHeaders = true;
2747             }
2748             else {
2749                 this.hasHeaders = true;
2750             }
2751         },
2752
2753
2754         setHeader:function(o)
2755         {
2756             if (this.hasDefaultHeaders) {
2757                 for (var prop in this.defaultHeaders) {
2758                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2759                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2760                     }
2761                 }
2762             }
2763
2764             if (this.hasHeaders) {
2765                 for (var prop in this.headers) {
2766                     if (this.headers.hasOwnProperty(prop)) {
2767                         o.conn.setRequestHeader(prop, this.headers[prop]);
2768                     }
2769                 }
2770                 this.headers = {};
2771                 this.hasHeaders = false;
2772             }
2773         },
2774
2775         resetDefaultHeaders:function() {
2776             delete this.defaultHeaders;
2777             this.defaultHeaders = {};
2778             this.hasDefaultHeaders = false;
2779         },
2780
2781         abort:function(o, callback, isTimeout)
2782         {
2783             if(this.isCallInProgress(o)) {
2784                 o.conn.abort();
2785                 window.clearInterval(this.poll[o.tId]);
2786                 delete this.poll[o.tId];
2787                 if (isTimeout) {
2788                     delete this.timeout[o.tId];
2789                 }
2790
2791                 this.handleTransactionResponse(o, callback, true);
2792
2793                 return true;
2794             }
2795             else {
2796                 return false;
2797             }
2798         },
2799
2800
2801         isCallInProgress:function(o)
2802         {
2803             if (o && o.conn) {
2804                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2805             }
2806             else {
2807
2808                 return false;
2809             }
2810         },
2811
2812
2813         releaseObject:function(o)
2814         {
2815
2816             o.conn = null;
2817
2818             o = null;
2819         },
2820
2821         activeX:[
2822         'MSXML2.XMLHTTP.3.0',
2823         'MSXML2.XMLHTTP',
2824         'Microsoft.XMLHTTP'
2825         ]
2826
2827
2828     };
2829 })();/*
2830  * Portions of this file are based on pieces of Yahoo User Interface Library
2831  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2832  * YUI licensed under the BSD License:
2833  * http://developer.yahoo.net/yui/license.txt
2834  * <script type="text/javascript">
2835  *
2836  */
2837
2838 Roo.lib.Region = function(t, r, b, l) {
2839     this.top = t;
2840     this[1] = t;
2841     this.right = r;
2842     this.bottom = b;
2843     this.left = l;
2844     this[0] = l;
2845 };
2846
2847
2848 Roo.lib.Region.prototype = {
2849     contains : function(region) {
2850         return ( region.left >= this.left &&
2851                  region.right <= this.right &&
2852                  region.top >= this.top &&
2853                  region.bottom <= this.bottom    );
2854
2855     },
2856
2857     getArea : function() {
2858         return ( (this.bottom - this.top) * (this.right - this.left) );
2859     },
2860
2861     intersect : function(region) {
2862         var t = Math.max(this.top, region.top);
2863         var r = Math.min(this.right, region.right);
2864         var b = Math.min(this.bottom, region.bottom);
2865         var l = Math.max(this.left, region.left);
2866
2867         if (b >= t && r >= l) {
2868             return new Roo.lib.Region(t, r, b, l);
2869         } else {
2870             return null;
2871         }
2872     },
2873     union : function(region) {
2874         var t = Math.min(this.top, region.top);
2875         var r = Math.max(this.right, region.right);
2876         var b = Math.max(this.bottom, region.bottom);
2877         var l = Math.min(this.left, region.left);
2878
2879         return new Roo.lib.Region(t, r, b, l);
2880     },
2881
2882     adjust : function(t, l, b, r) {
2883         this.top += t;
2884         this.left += l;
2885         this.right += r;
2886         this.bottom += b;
2887         return this;
2888     }
2889 };
2890
2891 Roo.lib.Region.getRegion = function(el) {
2892     var p = Roo.lib.Dom.getXY(el);
2893
2894     var t = p[1];
2895     var r = p[0] + el.offsetWidth;
2896     var b = p[1] + el.offsetHeight;
2897     var l = p[0];
2898
2899     return new Roo.lib.Region(t, r, b, l);
2900 };
2901 /*
2902  * Portions of this file are based on pieces of Yahoo User Interface Library
2903  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2904  * YUI licensed under the BSD License:
2905  * http://developer.yahoo.net/yui/license.txt
2906  * <script type="text/javascript">
2907  *
2908  */
2909 //@@dep Roo.lib.Region
2910
2911
2912 Roo.lib.Point = function(x, y) {
2913     if (x instanceof Array) {
2914         y = x[1];
2915         x = x[0];
2916     }
2917     this.x = this.right = this.left = this[0] = x;
2918     this.y = this.top = this.bottom = this[1] = y;
2919 };
2920
2921 Roo.lib.Point.prototype = new Roo.lib.Region();
2922 /*
2923  * Portions of this file are based on pieces of Yahoo User Interface Library
2924  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2925  * YUI licensed under the BSD License:
2926  * http://developer.yahoo.net/yui/license.txt
2927  * <script type="text/javascript">
2928  *
2929  */
2930  
2931 (function() {   
2932
2933     Roo.lib.Anim = {
2934         scroll : function(el, args, duration, easing, cb, scope) {
2935             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2936         },
2937
2938         motion : function(el, args, duration, easing, cb, scope) {
2939             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2940         },
2941
2942         color : function(el, args, duration, easing, cb, scope) {
2943             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2944         },
2945
2946         run : function(el, args, duration, easing, cb, scope, type) {
2947             type = type || Roo.lib.AnimBase;
2948             if (typeof easing == "string") {
2949                 easing = Roo.lib.Easing[easing];
2950             }
2951             var anim = new type(el, args, duration, easing);
2952             anim.animateX(function() {
2953                 Roo.callback(cb, scope);
2954             });
2955             return anim;
2956         }
2957     };
2958 })();/*
2959  * Portions of this file are based on pieces of Yahoo User Interface Library
2960  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2961  * YUI licensed under the BSD License:
2962  * http://developer.yahoo.net/yui/license.txt
2963  * <script type="text/javascript">
2964  *
2965  */
2966
2967 (function() {    
2968     var libFlyweight;
2969     
2970     function fly(el) {
2971         if (!libFlyweight) {
2972             libFlyweight = new Roo.Element.Flyweight();
2973         }
2974         libFlyweight.dom = el;
2975         return libFlyweight;
2976     }
2977
2978     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2979     
2980    
2981     
2982     Roo.lib.AnimBase = function(el, attributes, duration, method) {
2983         if (el) {
2984             this.init(el, attributes, duration, method);
2985         }
2986     };
2987
2988     Roo.lib.AnimBase.fly = fly;
2989     
2990     
2991     
2992     Roo.lib.AnimBase.prototype = {
2993
2994         toString: function() {
2995             var el = this.getEl();
2996             var id = el.id || el.tagName;
2997             return ("Anim " + id);
2998         },
2999
3000         patterns: {
3001             noNegatives:        /width|height|opacity|padding/i,
3002             offsetAttribute:  /^((width|height)|(top|left))$/,
3003             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3004             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3005         },
3006
3007
3008         doMethod: function(attr, start, end) {
3009             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3010         },
3011
3012
3013         setAttribute: function(attr, val, unit) {
3014             if (this.patterns.noNegatives.test(attr)) {
3015                 val = (val > 0) ? val : 0;
3016             }
3017
3018             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3019         },
3020
3021
3022         getAttribute: function(attr) {
3023             var el = this.getEl();
3024             var val = fly(el).getStyle(attr);
3025
3026             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3027                 return parseFloat(val);
3028             }
3029
3030             var a = this.patterns.offsetAttribute.exec(attr) || [];
3031             var pos = !!( a[3] );
3032             var box = !!( a[2] );
3033
3034
3035             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3036                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3037             } else {
3038                 val = 0;
3039             }
3040
3041             return val;
3042         },
3043
3044
3045         getDefaultUnit: function(attr) {
3046             if (this.patterns.defaultUnit.test(attr)) {
3047                 return 'px';
3048             }
3049
3050             return '';
3051         },
3052
3053         animateX : function(callback, scope) {
3054             var f = function() {
3055                 this.onComplete.removeListener(f);
3056                 if (typeof callback == "function") {
3057                     callback.call(scope || this, this);
3058                 }
3059             };
3060             this.onComplete.addListener(f, this);
3061             this.animate();
3062         },
3063
3064
3065         setRuntimeAttribute: function(attr) {
3066             var start;
3067             var end;
3068             var attributes = this.attributes;
3069
3070             this.runtimeAttributes[attr] = {};
3071
3072             var isset = function(prop) {
3073                 return (typeof prop !== 'undefined');
3074             };
3075
3076             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3077                 return false;
3078             }
3079
3080             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3081
3082
3083             if (isset(attributes[attr]['to'])) {
3084                 end = attributes[attr]['to'];
3085             } else if (isset(attributes[attr]['by'])) {
3086                 if (start.constructor == Array) {
3087                     end = [];
3088                     for (var i = 0, len = start.length; i < len; ++i) {
3089                         end[i] = start[i] + attributes[attr]['by'][i];
3090                     }
3091                 } else {
3092                     end = start + attributes[attr]['by'];
3093                 }
3094             }
3095
3096             this.runtimeAttributes[attr].start = start;
3097             this.runtimeAttributes[attr].end = end;
3098
3099
3100             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3101         },
3102
3103
3104         init: function(el, attributes, duration, method) {
3105
3106             var isAnimated = false;
3107
3108
3109             var startTime = null;
3110
3111
3112             var actualFrames = 0;
3113
3114
3115             el = Roo.getDom(el);
3116
3117
3118             this.attributes = attributes || {};
3119
3120
3121             this.duration = duration || 1;
3122
3123
3124             this.method = method || Roo.lib.Easing.easeNone;
3125
3126
3127             this.useSeconds = true;
3128
3129
3130             this.currentFrame = 0;
3131
3132
3133             this.totalFrames = Roo.lib.AnimMgr.fps;
3134
3135
3136             this.getEl = function() {
3137                 return el;
3138             };
3139
3140
3141             this.isAnimated = function() {
3142                 return isAnimated;
3143             };
3144
3145
3146             this.getStartTime = function() {
3147                 return startTime;
3148             };
3149
3150             this.runtimeAttributes = {};
3151
3152
3153             this.animate = function() {
3154                 if (this.isAnimated()) {
3155                     return false;
3156                 }
3157
3158                 this.currentFrame = 0;
3159
3160                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3161
3162                 Roo.lib.AnimMgr.registerElement(this);
3163             };
3164
3165
3166             this.stop = function(finish) {
3167                 if (finish) {
3168                     this.currentFrame = this.totalFrames;
3169                     this._onTween.fire();
3170                 }
3171                 Roo.lib.AnimMgr.stop(this);
3172             };
3173
3174             var onStart = function() {
3175                 this.onStart.fire();
3176
3177                 this.runtimeAttributes = {};
3178                 for (var attr in this.attributes) {
3179                     this.setRuntimeAttribute(attr);
3180                 }
3181
3182                 isAnimated = true;
3183                 actualFrames = 0;
3184                 startTime = new Date();
3185             };
3186
3187
3188             var onTween = function() {
3189                 var data = {
3190                     duration: new Date() - this.getStartTime(),
3191                     currentFrame: this.currentFrame
3192                 };
3193
3194                 data.toString = function() {
3195                     return (
3196                             'duration: ' + data.duration +
3197                             ', currentFrame: ' + data.currentFrame
3198                             );
3199                 };
3200
3201                 this.onTween.fire(data);
3202
3203                 var runtimeAttributes = this.runtimeAttributes;
3204
3205                 for (var attr in runtimeAttributes) {
3206                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3207                 }
3208
3209                 actualFrames += 1;
3210             };
3211
3212             var onComplete = function() {
3213                 var actual_duration = (new Date() - startTime) / 1000 ;
3214
3215                 var data = {
3216                     duration: actual_duration,
3217                     frames: actualFrames,
3218                     fps: actualFrames / actual_duration
3219                 };
3220
3221                 data.toString = function() {
3222                     return (
3223                             'duration: ' + data.duration +
3224                             ', frames: ' + data.frames +
3225                             ', fps: ' + data.fps
3226                             );
3227                 };
3228
3229                 isAnimated = false;
3230                 actualFrames = 0;
3231                 this.onComplete.fire(data);
3232             };
3233
3234
3235             this._onStart = new Roo.util.Event(this);
3236             this.onStart = new Roo.util.Event(this);
3237             this.onTween = new Roo.util.Event(this);
3238             this._onTween = new Roo.util.Event(this);
3239             this.onComplete = new Roo.util.Event(this);
3240             this._onComplete = new Roo.util.Event(this);
3241             this._onStart.addListener(onStart);
3242             this._onTween.addListener(onTween);
3243             this._onComplete.addListener(onComplete);
3244         }
3245     };
3246 })();
3247 /*
3248  * Portions of this file are based on pieces of Yahoo User Interface Library
3249  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3250  * YUI licensed under the BSD License:
3251  * http://developer.yahoo.net/yui/license.txt
3252  * <script type="text/javascript">
3253  *
3254  */
3255
3256 Roo.lib.AnimMgr = new function() {
3257
3258         var thread = null;
3259
3260
3261         var queue = [];
3262
3263
3264         var tweenCount = 0;
3265
3266
3267         this.fps = 1000;
3268
3269
3270         this.delay = 1;
3271
3272
3273         this.registerElement = function(tween) {
3274             queue[queue.length] = tween;
3275             tweenCount += 1;
3276             tween._onStart.fire();
3277             this.start();
3278         };
3279
3280
3281         this.unRegister = function(tween, index) {
3282             tween._onComplete.fire();
3283             index = index || getIndex(tween);
3284             if (index != -1) {
3285                 queue.splice(index, 1);
3286             }
3287
3288             tweenCount -= 1;
3289             if (tweenCount <= 0) {
3290                 this.stop();
3291             }
3292         };
3293
3294
3295         this.start = function() {
3296             if (thread === null) {
3297                 thread = setInterval(this.run, this.delay);
3298             }
3299         };
3300
3301
3302         this.stop = function(tween) {
3303             if (!tween) {
3304                 clearInterval(thread);
3305
3306                 for (var i = 0, len = queue.length; i < len; ++i) {
3307                     if (queue[0].isAnimated()) {
3308                         this.unRegister(queue[0], 0);
3309                     }
3310                 }
3311
3312                 queue = [];
3313                 thread = null;
3314                 tweenCount = 0;
3315             }
3316             else {
3317                 this.unRegister(tween);
3318             }
3319         };
3320
3321
3322         this.run = function() {
3323             for (var i = 0, len = queue.length; i < len; ++i) {
3324                 var tween = queue[i];
3325                 if (!tween || !tween.isAnimated()) {
3326                     continue;
3327                 }
3328
3329                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3330                 {
3331                     tween.currentFrame += 1;
3332
3333                     if (tween.useSeconds) {
3334                         correctFrame(tween);
3335                     }
3336                     tween._onTween.fire();
3337                 }
3338                 else {
3339                     Roo.lib.AnimMgr.stop(tween, i);
3340                 }
3341             }
3342         };
3343
3344         var getIndex = function(anim) {
3345             for (var i = 0, len = queue.length; i < len; ++i) {
3346                 if (queue[i] == anim) {
3347                     return i;
3348                 }
3349             }
3350             return -1;
3351         };
3352
3353
3354         var correctFrame = function(tween) {
3355             var frames = tween.totalFrames;
3356             var frame = tween.currentFrame;
3357             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3358             var elapsed = (new Date() - tween.getStartTime());
3359             var tweak = 0;
3360
3361             if (elapsed < tween.duration * 1000) {
3362                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3363             } else {
3364                 tweak = frames - (frame + 1);
3365             }
3366             if (tweak > 0 && isFinite(tweak)) {
3367                 if (tween.currentFrame + tweak >= frames) {
3368                     tweak = frames - (frame + 1);
3369                 }
3370
3371                 tween.currentFrame += tweak;
3372             }
3373         };
3374     };/*
3375  * Portions of this file are based on pieces of Yahoo User Interface Library
3376  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3377  * YUI licensed under the BSD License:
3378  * http://developer.yahoo.net/yui/license.txt
3379  * <script type="text/javascript">
3380  *
3381  */
3382 Roo.lib.Bezier = new function() {
3383
3384         this.getPosition = function(points, t) {
3385             var n = points.length;
3386             var tmp = [];
3387
3388             for (var i = 0; i < n; ++i) {
3389                 tmp[i] = [points[i][0], points[i][1]];
3390             }
3391
3392             for (var j = 1; j < n; ++j) {
3393                 for (i = 0; i < n - j; ++i) {
3394                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3395                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3396                 }
3397             }
3398
3399             return [ tmp[0][0], tmp[0][1] ];
3400
3401         };
3402     };/*
3403  * Portions of this file are based on pieces of Yahoo User Interface Library
3404  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3405  * YUI licensed under the BSD License:
3406  * http://developer.yahoo.net/yui/license.txt
3407  * <script type="text/javascript">
3408  *
3409  */
3410 (function() {
3411
3412     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3413         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3414     };
3415
3416     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3417
3418     var fly = Roo.lib.AnimBase.fly;
3419     var Y = Roo.lib;
3420     var superclass = Y.ColorAnim.superclass;
3421     var proto = Y.ColorAnim.prototype;
3422
3423     proto.toString = function() {
3424         var el = this.getEl();
3425         var id = el.id || el.tagName;
3426         return ("ColorAnim " + id);
3427     };
3428
3429     proto.patterns.color = /color$/i;
3430     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3431     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3432     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3433     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3434
3435
3436     proto.parseColor = function(s) {
3437         if (s.length == 3) {
3438             return s;
3439         }
3440
3441         var c = this.patterns.hex.exec(s);
3442         if (c && c.length == 4) {
3443             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3444         }
3445
3446         c = this.patterns.rgb.exec(s);
3447         if (c && c.length == 4) {
3448             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3449         }
3450
3451         c = this.patterns.hex3.exec(s);
3452         if (c && c.length == 4) {
3453             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3454         }
3455
3456         return null;
3457     };
3458     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3459     proto.getAttribute = function(attr) {
3460         var el = this.getEl();
3461         if (this.patterns.color.test(attr)) {
3462             var val = fly(el).getStyle(attr);
3463
3464             if (this.patterns.transparent.test(val)) {
3465                 var parent = el.parentNode;
3466                 val = fly(parent).getStyle(attr);
3467
3468                 while (parent && this.patterns.transparent.test(val)) {
3469                     parent = parent.parentNode;
3470                     val = fly(parent).getStyle(attr);
3471                     if (parent.tagName.toUpperCase() == 'HTML') {
3472                         val = '#fff';
3473                     }
3474                 }
3475             }
3476         } else {
3477             val = superclass.getAttribute.call(this, attr);
3478         }
3479
3480         return val;
3481     };
3482     proto.getAttribute = function(attr) {
3483         var el = this.getEl();
3484         if (this.patterns.color.test(attr)) {
3485             var val = fly(el).getStyle(attr);
3486
3487             if (this.patterns.transparent.test(val)) {
3488                 var parent = el.parentNode;
3489                 val = fly(parent).getStyle(attr);
3490
3491                 while (parent && this.patterns.transparent.test(val)) {
3492                     parent = parent.parentNode;
3493                     val = fly(parent).getStyle(attr);
3494                     if (parent.tagName.toUpperCase() == 'HTML') {
3495                         val = '#fff';
3496                     }
3497                 }
3498             }
3499         } else {
3500             val = superclass.getAttribute.call(this, attr);
3501         }
3502
3503         return val;
3504     };
3505
3506     proto.doMethod = function(attr, start, end) {
3507         var val;
3508
3509         if (this.patterns.color.test(attr)) {
3510             val = [];
3511             for (var i = 0, len = start.length; i < len; ++i) {
3512                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3513             }
3514
3515             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3516         }
3517         else {
3518             val = superclass.doMethod.call(this, attr, start, end);
3519         }
3520
3521         return val;
3522     };
3523
3524     proto.setRuntimeAttribute = function(attr) {
3525         superclass.setRuntimeAttribute.call(this, attr);
3526
3527         if (this.patterns.color.test(attr)) {
3528             var attributes = this.attributes;
3529             var start = this.parseColor(this.runtimeAttributes[attr].start);
3530             var end = this.parseColor(this.runtimeAttributes[attr].end);
3531
3532             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3533                 end = this.parseColor(attributes[attr].by);
3534
3535                 for (var i = 0, len = start.length; i < len; ++i) {
3536                     end[i] = start[i] + end[i];
3537                 }
3538             }
3539
3540             this.runtimeAttributes[attr].start = start;
3541             this.runtimeAttributes[attr].end = end;
3542         }
3543     };
3544 })();
3545
3546 /*
3547  * Portions of this file are based on pieces of Yahoo User Interface Library
3548  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3549  * YUI licensed under the BSD License:
3550  * http://developer.yahoo.net/yui/license.txt
3551  * <script type="text/javascript">
3552  *
3553  */
3554 Roo.lib.Easing = {
3555
3556
3557     easeNone: function (t, b, c, d) {
3558         return c * t / d + b;
3559     },
3560
3561
3562     easeIn: function (t, b, c, d) {
3563         return c * (t /= d) * t + b;
3564     },
3565
3566
3567     easeOut: function (t, b, c, d) {
3568         return -c * (t /= d) * (t - 2) + b;
3569     },
3570
3571
3572     easeBoth: function (t, b, c, d) {
3573         if ((t /= d / 2) < 1) {
3574             return c / 2 * t * t + b;
3575         }
3576
3577         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3578     },
3579
3580
3581     easeInStrong: function (t, b, c, d) {
3582         return c * (t /= d) * t * t * t + b;
3583     },
3584
3585
3586     easeOutStrong: function (t, b, c, d) {
3587         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3588     },
3589
3590
3591     easeBothStrong: function (t, b, c, d) {
3592         if ((t /= d / 2) < 1) {
3593             return c / 2 * t * t * t * t + b;
3594         }
3595
3596         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3597     },
3598
3599
3600
3601     elasticIn: function (t, b, c, d, a, p) {
3602         if (t == 0) {
3603             return b;
3604         }
3605         if ((t /= d) == 1) {
3606             return b + c;
3607         }
3608         if (!p) {
3609             p = d * .3;
3610         }
3611
3612         if (!a || a < Math.abs(c)) {
3613             a = c;
3614             var s = p / 4;
3615         }
3616         else {
3617             var s = p / (2 * Math.PI) * Math.asin(c / a);
3618         }
3619
3620         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3621     },
3622
3623
3624     elasticOut: function (t, b, c, d, a, p) {
3625         if (t == 0) {
3626             return b;
3627         }
3628         if ((t /= d) == 1) {
3629             return b + c;
3630         }
3631         if (!p) {
3632             p = d * .3;
3633         }
3634
3635         if (!a || a < Math.abs(c)) {
3636             a = c;
3637             var s = p / 4;
3638         }
3639         else {
3640             var s = p / (2 * Math.PI) * Math.asin(c / a);
3641         }
3642
3643         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3644     },
3645
3646
3647     elasticBoth: function (t, b, c, d, a, p) {
3648         if (t == 0) {
3649             return b;
3650         }
3651
3652         if ((t /= d / 2) == 2) {
3653             return b + c;
3654         }
3655
3656         if (!p) {
3657             p = d * (.3 * 1.5);
3658         }
3659
3660         if (!a || a < Math.abs(c)) {
3661             a = c;
3662             var s = p / 4;
3663         }
3664         else {
3665             var s = p / (2 * Math.PI) * Math.asin(c / a);
3666         }
3667
3668         if (t < 1) {
3669             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3670                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3671         }
3672         return a * Math.pow(2, -10 * (t -= 1)) *
3673                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3674     },
3675
3676
3677
3678     backIn: function (t, b, c, d, s) {
3679         if (typeof s == 'undefined') {
3680             s = 1.70158;
3681         }
3682         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3683     },
3684
3685
3686     backOut: function (t, b, c, d, s) {
3687         if (typeof s == 'undefined') {
3688             s = 1.70158;
3689         }
3690         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3691     },
3692
3693
3694     backBoth: function (t, b, c, d, s) {
3695         if (typeof s == 'undefined') {
3696             s = 1.70158;
3697         }
3698
3699         if ((t /= d / 2 ) < 1) {
3700             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3701         }
3702         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3703     },
3704
3705
3706     bounceIn: function (t, b, c, d) {
3707         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3708     },
3709
3710
3711     bounceOut: function (t, b, c, d) {
3712         if ((t /= d) < (1 / 2.75)) {
3713             return c * (7.5625 * t * t) + b;
3714         } else if (t < (2 / 2.75)) {
3715             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3716         } else if (t < (2.5 / 2.75)) {
3717             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3718         }
3719         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3720     },
3721
3722
3723     bounceBoth: function (t, b, c, d) {
3724         if (t < d / 2) {
3725             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3726         }
3727         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3728     }
3729 };/*
3730  * Portions of this file are based on pieces of Yahoo User Interface Library
3731  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3732  * YUI licensed under the BSD License:
3733  * http://developer.yahoo.net/yui/license.txt
3734  * <script type="text/javascript">
3735  *
3736  */
3737     (function() {
3738         Roo.lib.Motion = function(el, attributes, duration, method) {
3739             if (el) {
3740                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3741             }
3742         };
3743
3744         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3745
3746
3747         var Y = Roo.lib;
3748         var superclass = Y.Motion.superclass;
3749         var proto = Y.Motion.prototype;
3750
3751         proto.toString = function() {
3752             var el = this.getEl();
3753             var id = el.id || el.tagName;
3754             return ("Motion " + id);
3755         };
3756
3757         proto.patterns.points = /^points$/i;
3758
3759         proto.setAttribute = function(attr, val, unit) {
3760             if (this.patterns.points.test(attr)) {
3761                 unit = unit || 'px';
3762                 superclass.setAttribute.call(this, 'left', val[0], unit);
3763                 superclass.setAttribute.call(this, 'top', val[1], unit);
3764             } else {
3765                 superclass.setAttribute.call(this, attr, val, unit);
3766             }
3767         };
3768
3769         proto.getAttribute = function(attr) {
3770             if (this.patterns.points.test(attr)) {
3771                 var val = [
3772                         superclass.getAttribute.call(this, 'left'),
3773                         superclass.getAttribute.call(this, 'top')
3774                         ];
3775             } else {
3776                 val = superclass.getAttribute.call(this, attr);
3777             }
3778
3779             return val;
3780         };
3781
3782         proto.doMethod = function(attr, start, end) {
3783             var val = null;
3784
3785             if (this.patterns.points.test(attr)) {
3786                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3787                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3788             } else {
3789                 val = superclass.doMethod.call(this, attr, start, end);
3790             }
3791             return val;
3792         };
3793
3794         proto.setRuntimeAttribute = function(attr) {
3795             if (this.patterns.points.test(attr)) {
3796                 var el = this.getEl();
3797                 var attributes = this.attributes;
3798                 var start;
3799                 var control = attributes['points']['control'] || [];
3800                 var end;
3801                 var i, len;
3802
3803                 if (control.length > 0 && !(control[0] instanceof Array)) {
3804                     control = [control];
3805                 } else {
3806                     var tmp = [];
3807                     for (i = 0,len = control.length; i < len; ++i) {
3808                         tmp[i] = control[i];
3809                     }
3810                     control = tmp;
3811                 }
3812
3813                 Roo.fly(el).position();
3814
3815                 if (isset(attributes['points']['from'])) {
3816                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3817                 }
3818                 else {
3819                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3820                 }
3821
3822                 start = this.getAttribute('points');
3823
3824
3825                 if (isset(attributes['points']['to'])) {
3826                     end = translateValues.call(this, attributes['points']['to'], start);
3827
3828                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3829                     for (i = 0,len = control.length; i < len; ++i) {
3830                         control[i] = translateValues.call(this, control[i], start);
3831                     }
3832
3833
3834                 } else if (isset(attributes['points']['by'])) {
3835                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3836
3837                     for (i = 0,len = control.length; i < len; ++i) {
3838                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3839                     }
3840                 }
3841
3842                 this.runtimeAttributes[attr] = [start];
3843
3844                 if (control.length > 0) {
3845                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3846                 }
3847
3848                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3849             }
3850             else {
3851                 superclass.setRuntimeAttribute.call(this, attr);
3852             }
3853         };
3854
3855         var translateValues = function(val, start) {
3856             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3857             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3858
3859             return val;
3860         };
3861
3862         var isset = function(prop) {
3863             return (typeof prop !== 'undefined');
3864         };
3865     })();
3866 /*
3867  * Portions of this file are based on pieces of Yahoo User Interface Library
3868  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3869  * YUI licensed under the BSD License:
3870  * http://developer.yahoo.net/yui/license.txt
3871  * <script type="text/javascript">
3872  *
3873  */
3874     (function() {
3875         Roo.lib.Scroll = function(el, attributes, duration, method) {
3876             if (el) {
3877                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3878             }
3879         };
3880
3881         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3882
3883
3884         var Y = Roo.lib;
3885         var superclass = Y.Scroll.superclass;
3886         var proto = Y.Scroll.prototype;
3887
3888         proto.toString = function() {
3889             var el = this.getEl();
3890             var id = el.id || el.tagName;
3891             return ("Scroll " + id);
3892         };
3893
3894         proto.doMethod = function(attr, start, end) {
3895             var val = null;
3896
3897             if (attr == 'scroll') {
3898                 val = [
3899                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3900                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3901                         ];
3902
3903             } else {
3904                 val = superclass.doMethod.call(this, attr, start, end);
3905             }
3906             return val;
3907         };
3908
3909         proto.getAttribute = function(attr) {
3910             var val = null;
3911             var el = this.getEl();
3912
3913             if (attr == 'scroll') {
3914                 val = [ el.scrollLeft, el.scrollTop ];
3915             } else {
3916                 val = superclass.getAttribute.call(this, attr);
3917             }
3918
3919             return val;
3920         };
3921
3922         proto.setAttribute = function(attr, val, unit) {
3923             var el = this.getEl();
3924
3925             if (attr == 'scroll') {
3926                 el.scrollLeft = val[0];
3927                 el.scrollTop = val[1];
3928             } else {
3929                 superclass.setAttribute.call(this, attr, val, unit);
3930             }
3931         };
3932     })();
3933 /*
3934  * Based on:
3935  * Ext JS Library 1.1.1
3936  * Copyright(c) 2006-2007, Ext JS, LLC.
3937  *
3938  * Originally Released Under LGPL - original licence link has changed is not relivant.
3939  *
3940  * Fork - LGPL
3941  * <script type="text/javascript">
3942  */
3943  
3944
3945 /**
3946  * @class Roo.DomHelper
3947  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3948  * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3949  * @singleton
3950  */
3951 Roo.DomHelper = function(){
3952     var tempTableEl = null;
3953     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3954     var tableRe = /^table|tbody|tr|td$/i;
3955     var xmlns = {};
3956     // build as innerHTML where available
3957     /** @ignore */
3958     var createHtml = function(o){
3959         if(typeof o == 'string'){
3960             return o;
3961         }
3962         var b = "";
3963         if(!o.tag){
3964             o.tag = "div";
3965         }
3966         b += "<" + o.tag;
3967         for(var attr in o){
3968             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3969             if(attr == "style"){
3970                 var s = o["style"];
3971                 if(typeof s == "function"){
3972                     s = s.call();
3973                 }
3974                 if(typeof s == "string"){
3975                     b += ' style="' + s + '"';
3976                 }else if(typeof s == "object"){
3977                     b += ' style="';
3978                     for(var key in s){
3979                         if(typeof s[key] != "function"){
3980                             b += key + ":" + s[key] + ";";
3981                         }
3982                     }
3983                     b += '"';
3984                 }
3985             }else{
3986                 if(attr == "cls"){
3987                     b += ' class="' + o["cls"] + '"';
3988                 }else if(attr == "htmlFor"){
3989                     b += ' for="' + o["htmlFor"] + '"';
3990                 }else{
3991                     b += " " + attr + '="' + o[attr] + '"';
3992                 }
3993             }
3994         }
3995         if(emptyTags.test(o.tag)){
3996             b += "/>";
3997         }else{
3998             b += ">";
3999             var cn = o.children || o.cn;
4000             if(cn){
4001                 //http://bugs.kde.org/show_bug.cgi?id=71506
4002                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4003                     for(var i = 0, len = cn.length; i < len; i++) {
4004                         b += createHtml(cn[i], b);
4005                     }
4006                 }else{
4007                     b += createHtml(cn, b);
4008                 }
4009             }
4010             if(o.html){
4011                 b += o.html;
4012             }
4013             b += "</" + o.tag + ">";
4014         }
4015         return b;
4016     };
4017
4018     // build as dom
4019     /** @ignore */
4020     var createDom = function(o, parentNode){
4021          
4022         // defininition craeted..
4023         var ns = false;
4024         if (o.ns && o.ns != 'html') {
4025                
4026             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4027                 xmlns[o.ns] = o.xmlns;
4028                 ns = o.xmlns;
4029             }
4030             if (typeof(xmlns[o.ns]) == 'undefined') {
4031                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4032             }
4033             ns = xmlns[o.ns];
4034         }
4035         
4036         
4037         if (typeof(o) == 'string') {
4038             return parentNode.appendChild(document.createTextNode(o));
4039         }
4040         o.tag = o.tag || div;
4041         if (o.ns && Roo.isIE) {
4042             ns = false;
4043             o.tag = o.ns + ':' + o.tag;
4044             
4045         }
4046         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4047         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4048         for(var attr in o){
4049             
4050             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4051                     attr == "style" || typeof o[attr] == "function") continue;
4052                     
4053             if(attr=="cls" && Roo.isIE){
4054                 el.className = o["cls"];
4055             }else{
4056                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4057                 else el[attr] = o[attr];
4058             }
4059         }
4060         Roo.DomHelper.applyStyles(el, o.style);
4061         var cn = o.children || o.cn;
4062         if(cn){
4063             //http://bugs.kde.org/show_bug.cgi?id=71506
4064              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4065                 for(var i = 0, len = cn.length; i < len; i++) {
4066                     createDom(cn[i], el);
4067                 }
4068             }else{
4069                 createDom(cn, el);
4070             }
4071         }
4072         if(o.html){
4073             el.innerHTML = o.html;
4074         }
4075         if(parentNode){
4076            parentNode.appendChild(el);
4077         }
4078         return el;
4079     };
4080
4081     var ieTable = function(depth, s, h, e){
4082         tempTableEl.innerHTML = [s, h, e].join('');
4083         var i = -1, el = tempTableEl;
4084         while(++i < depth){
4085             el = el.firstChild;
4086         }
4087         return el;
4088     };
4089
4090     // kill repeat to save bytes
4091     var ts = '<table>',
4092         te = '</table>',
4093         tbs = ts+'<tbody>',
4094         tbe = '</tbody>'+te,
4095         trs = tbs + '<tr>',
4096         tre = '</tr>'+tbe;
4097
4098     /**
4099      * @ignore
4100      * Nasty code for IE's broken table implementation
4101      */
4102     var insertIntoTable = function(tag, where, el, html){
4103         if(!tempTableEl){
4104             tempTableEl = document.createElement('div');
4105         }
4106         var node;
4107         var before = null;
4108         if(tag == 'td'){
4109             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4110                 return;
4111             }
4112             if(where == 'beforebegin'){
4113                 before = el;
4114                 el = el.parentNode;
4115             } else{
4116                 before = el.nextSibling;
4117                 el = el.parentNode;
4118             }
4119             node = ieTable(4, trs, html, tre);
4120         }
4121         else if(tag == 'tr'){
4122             if(where == 'beforebegin'){
4123                 before = el;
4124                 el = el.parentNode;
4125                 node = ieTable(3, tbs, html, tbe);
4126             } else if(where == 'afterend'){
4127                 before = el.nextSibling;
4128                 el = el.parentNode;
4129                 node = ieTable(3, tbs, html, tbe);
4130             } else{ // INTO a TR
4131                 if(where == 'afterbegin'){
4132                     before = el.firstChild;
4133                 }
4134                 node = ieTable(4, trs, html, tre);
4135             }
4136         } else if(tag == 'tbody'){
4137             if(where == 'beforebegin'){
4138                 before = el;
4139                 el = el.parentNode;
4140                 node = ieTable(2, ts, html, te);
4141             } else if(where == 'afterend'){
4142                 before = el.nextSibling;
4143                 el = el.parentNode;
4144                 node = ieTable(2, ts, html, te);
4145             } else{
4146                 if(where == 'afterbegin'){
4147                     before = el.firstChild;
4148                 }
4149                 node = ieTable(3, tbs, html, tbe);
4150             }
4151         } else{ // TABLE
4152             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4153                 return;
4154             }
4155             if(where == 'afterbegin'){
4156                 before = el.firstChild;
4157             }
4158             node = ieTable(2, ts, html, te);
4159         }
4160         el.insertBefore(node, before);
4161         return node;
4162     };
4163
4164     return {
4165     /** True to force the use of DOM instead of html fragments @type Boolean */
4166     useDom : false,
4167
4168     /**
4169      * Returns the markup for the passed Element(s) config
4170      * @param {Object} o The Dom object spec (and children)
4171      * @return {String}
4172      */
4173     markup : function(o){
4174         return createHtml(o);
4175     },
4176
4177     /**
4178      * Applies a style specification to an element
4179      * @param {String/HTMLElement} el The element to apply styles to
4180      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4181      * a function which returns such a specification.
4182      */
4183     applyStyles : function(el, styles){
4184         if(styles){
4185            el = Roo.fly(el);
4186            if(typeof styles == "string"){
4187                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4188                var matches;
4189                while ((matches = re.exec(styles)) != null){
4190                    el.setStyle(matches[1], matches[2]);
4191                }
4192            }else if (typeof styles == "object"){
4193                for (var style in styles){
4194                   el.setStyle(style, styles[style]);
4195                }
4196            }else if (typeof styles == "function"){
4197                 Roo.DomHelper.applyStyles(el, styles.call());
4198            }
4199         }
4200     },
4201
4202     /**
4203      * Inserts an HTML fragment into the Dom
4204      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4205      * @param {HTMLElement} el The context element
4206      * @param {String} html The HTML fragmenet
4207      * @return {HTMLElement} The new node
4208      */
4209     insertHtml : function(where, el, html){
4210         where = where.toLowerCase();
4211         if(el.insertAdjacentHTML){
4212             if(tableRe.test(el.tagName)){
4213                 var rs;
4214                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4215                     return rs;
4216                 }
4217             }
4218             switch(where){
4219                 case "beforebegin":
4220                     el.insertAdjacentHTML('BeforeBegin', html);
4221                     return el.previousSibling;
4222                 case "afterbegin":
4223                     el.insertAdjacentHTML('AfterBegin', html);
4224                     return el.firstChild;
4225                 case "beforeend":
4226                     el.insertAdjacentHTML('BeforeEnd', html);
4227                     return el.lastChild;
4228                 case "afterend":
4229                     el.insertAdjacentHTML('AfterEnd', html);
4230                     return el.nextSibling;
4231             }
4232             throw 'Illegal insertion point -> "' + where + '"';
4233         }
4234         var range = el.ownerDocument.createRange();
4235         var frag;
4236         switch(where){
4237              case "beforebegin":
4238                 range.setStartBefore(el);
4239                 frag = range.createContextualFragment(html);
4240                 el.parentNode.insertBefore(frag, el);
4241                 return el.previousSibling;
4242              case "afterbegin":
4243                 if(el.firstChild){
4244                     range.setStartBefore(el.firstChild);
4245                     frag = range.createContextualFragment(html);
4246                     el.insertBefore(frag, el.firstChild);
4247                     return el.firstChild;
4248                 }else{
4249                     el.innerHTML = html;
4250                     return el.firstChild;
4251                 }
4252             case "beforeend":
4253                 if(el.lastChild){
4254                     range.setStartAfter(el.lastChild);
4255                     frag = range.createContextualFragment(html);
4256                     el.appendChild(frag);
4257                     return el.lastChild;
4258                 }else{
4259                     el.innerHTML = html;
4260                     return el.lastChild;
4261                 }
4262             case "afterend":
4263                 range.setStartAfter(el);
4264                 frag = range.createContextualFragment(html);
4265                 el.parentNode.insertBefore(frag, el.nextSibling);
4266                 return el.nextSibling;
4267             }
4268             throw 'Illegal insertion point -> "' + where + '"';
4269     },
4270
4271     /**
4272      * Creates new Dom element(s) and inserts them before el
4273      * @param {String/HTMLElement/Element} el The context element
4274      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4275      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4276      * @return {HTMLElement/Roo.Element} The new node
4277      */
4278     insertBefore : function(el, o, returnElement){
4279         return this.doInsert(el, o, returnElement, "beforeBegin");
4280     },
4281
4282     /**
4283      * Creates new Dom element(s) and inserts them after el
4284      * @param {String/HTMLElement/Element} el The context element
4285      * @param {Object} o The Dom object spec (and children)
4286      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4287      * @return {HTMLElement/Roo.Element} The new node
4288      */
4289     insertAfter : function(el, o, returnElement){
4290         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4291     },
4292
4293     /**
4294      * Creates new Dom element(s) and inserts them as the first child of el
4295      * @param {String/HTMLElement/Element} el The context element
4296      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4297      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4298      * @return {HTMLElement/Roo.Element} The new node
4299      */
4300     insertFirst : function(el, o, returnElement){
4301         return this.doInsert(el, o, returnElement, "afterBegin");
4302     },
4303
4304     // private
4305     doInsert : function(el, o, returnElement, pos, sibling){
4306         el = Roo.getDom(el);
4307         var newNode;
4308         if(this.useDom || o.ns){
4309             newNode = createDom(o, null);
4310             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4311         }else{
4312             var html = createHtml(o);
4313             newNode = this.insertHtml(pos, el, html);
4314         }
4315         return returnElement ? Roo.get(newNode, true) : newNode;
4316     },
4317
4318     /**
4319      * Creates new Dom element(s) and appends them to el
4320      * @param {String/HTMLElement/Element} el The context element
4321      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4322      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4323      * @return {HTMLElement/Roo.Element} The new node
4324      */
4325     append : function(el, o, returnElement){
4326         el = Roo.getDom(el);
4327         var newNode;
4328         if(this.useDom || o.ns){
4329             newNode = createDom(o, null);
4330             el.appendChild(newNode);
4331         }else{
4332             var html = createHtml(o);
4333             newNode = this.insertHtml("beforeEnd", el, html);
4334         }
4335         return returnElement ? Roo.get(newNode, true) : newNode;
4336     },
4337
4338     /**
4339      * Creates new Dom element(s) and overwrites the contents of el with them
4340      * @param {String/HTMLElement/Element} el The context element
4341      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4342      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4343      * @return {HTMLElement/Roo.Element} The new node
4344      */
4345     overwrite : function(el, o, returnElement){
4346         el = Roo.getDom(el);
4347         if (o.ns) {
4348           
4349             while (el.childNodes.length) {
4350                 el.removeChild(el.firstChild);
4351             }
4352             createDom(o, el);
4353         } else {
4354             el.innerHTML = createHtml(o);   
4355         }
4356         
4357         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4358     },
4359
4360     /**
4361      * Creates a new Roo.DomHelper.Template from the Dom object spec
4362      * @param {Object} o The Dom object spec (and children)
4363      * @return {Roo.DomHelper.Template} The new template
4364      */
4365     createTemplate : function(o){
4366         var html = createHtml(o);
4367         return new Roo.Template(html);
4368     }
4369     };
4370 }();
4371 /*
4372  * Based on:
4373  * Ext JS Library 1.1.1
4374  * Copyright(c) 2006-2007, Ext JS, LLC.
4375  *
4376  * Originally Released Under LGPL - original licence link has changed is not relivant.
4377  *
4378  * Fork - LGPL
4379  * <script type="text/javascript">
4380  */
4381  
4382 /**
4383 * @class Roo.Template
4384 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4385 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4386 * Usage:
4387 <pre><code>
4388 var t = new Roo.Template(
4389     '&lt;div name="{id}"&gt;',
4390         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
4391     '&lt;/div&gt;'
4392 );
4393 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4394 </code></pre>
4395 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
4396 * @constructor
4397 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4398 */
4399 Roo.Template = function(html){
4400     if(html instanceof Array){
4401         html = html.join("");
4402     }else if(arguments.length > 1){
4403         html = Array.prototype.join.call(arguments, "");
4404     }
4405     /**@private*/
4406     this.html = html;
4407     
4408 };
4409 Roo.Template.prototype = {
4410     /**
4411      * Returns an HTML fragment of this template with the specified values applied.
4412      * @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'})
4413      * @return {String} The HTML fragment
4414      */
4415     applyTemplate : function(values){
4416         if(this.compiled){
4417             return this.compiled(values);
4418         }
4419         var useF = this.disableFormats !== true;
4420         var fm = Roo.util.Format, tpl = this;
4421         var fn = function(m, name, format, args){
4422             if(format && useF){
4423                 if(format.substr(0, 5) == "this."){
4424                     return tpl.call(format.substr(5), values[name], values);
4425                 }else{
4426                     if(args){
4427                         // quoted values are required for strings in compiled templates, 
4428                         // but for non compiled we need to strip them
4429                         // quoted reversed for jsmin
4430                         var re = /^\s*['"](.*)["']\s*$/;
4431                         args = args.split(',');
4432                         for(var i = 0, len = args.length; i < len; i++){
4433                             args[i] = args[i].replace(re, "$1");
4434                         }
4435                         args = [values[name]].concat(args);
4436                     }else{
4437                         args = [values[name]];
4438                     }
4439                     return fm[format].apply(fm, args);
4440                 }
4441             }else{
4442                 return values[name] !== undefined ? values[name] : "";
4443             }
4444         };
4445         return this.html.replace(this.re, fn);
4446     },
4447     
4448     /**
4449      * Sets the HTML used as the template and optionally compiles it.
4450      * @param {String} html
4451      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4452      * @return {Roo.Template} this
4453      */
4454     set : function(html, compile){
4455         this.html = html;
4456         this.compiled = null;
4457         if(compile){
4458             this.compile();
4459         }
4460         return this;
4461     },
4462     
4463     /**
4464      * True to disable format functions (defaults to false)
4465      * @type Boolean
4466      */
4467     disableFormats : false,
4468     
4469     /**
4470     * The regular expression used to match template variables 
4471     * @type RegExp
4472     * @property 
4473     */
4474     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4475     
4476     /**
4477      * Compiles the template into an internal function, eliminating the RegEx overhead.
4478      * @return {Roo.Template} this
4479      */
4480     compile : function(){
4481         var fm = Roo.util.Format;
4482         var useF = this.disableFormats !== true;
4483         var sep = Roo.isGecko ? "+" : ",";
4484         var fn = function(m, name, format, args){
4485             if(format && useF){
4486                 args = args ? ',' + args : "";
4487                 if(format.substr(0, 5) != "this."){
4488                     format = "fm." + format + '(';
4489                 }else{
4490                     format = 'this.call("'+ format.substr(5) + '", ';
4491                     args = ", values";
4492                 }
4493             }else{
4494                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4495             }
4496             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4497         };
4498         var body;
4499         // branched to use + in gecko and [].join() in others
4500         if(Roo.isGecko){
4501             body = "this.compiled = function(values){ return '" +
4502                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4503                     "';};";
4504         }else{
4505             body = ["this.compiled = function(values){ return ['"];
4506             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4507             body.push("'].join('');};");
4508             body = body.join('');
4509         }
4510         /**
4511          * eval:var:values
4512          * eval:var:fm
4513          */
4514         eval(body);
4515         return this;
4516     },
4517     
4518     // private function used to call members
4519     call : function(fnName, value, allValues){
4520         return this[fnName](value, allValues);
4521     },
4522     
4523     /**
4524      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4525      * @param {String/HTMLElement/Roo.Element} el The context element
4526      * @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'})
4527      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4528      * @return {HTMLElement/Roo.Element} The new node or Element
4529      */
4530     insertFirst: function(el, values, returnElement){
4531         return this.doInsert('afterBegin', el, values, returnElement);
4532     },
4533
4534     /**
4535      * Applies the supplied values to the template and inserts the new node(s) before el.
4536      * @param {String/HTMLElement/Roo.Element} el The context element
4537      * @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'})
4538      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4539      * @return {HTMLElement/Roo.Element} The new node or Element
4540      */
4541     insertBefore: function(el, values, returnElement){
4542         return this.doInsert('beforeBegin', el, values, returnElement);
4543     },
4544
4545     /**
4546      * Applies the supplied values to the template and inserts the new node(s) after el.
4547      * @param {String/HTMLElement/Roo.Element} el The context element
4548      * @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'})
4549      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4550      * @return {HTMLElement/Roo.Element} The new node or Element
4551      */
4552     insertAfter : function(el, values, returnElement){
4553         return this.doInsert('afterEnd', el, values, returnElement);
4554     },
4555     
4556     /**
4557      * Applies the supplied values to the template and appends the new node(s) to el.
4558      * @param {String/HTMLElement/Roo.Element} el The context element
4559      * @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'})
4560      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4561      * @return {HTMLElement/Roo.Element} The new node or Element
4562      */
4563     append : function(el, values, returnElement){
4564         return this.doInsert('beforeEnd', el, values, returnElement);
4565     },
4566
4567     doInsert : function(where, el, values, returnEl){
4568         el = Roo.getDom(el);
4569         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4570         return returnEl ? Roo.get(newNode, true) : newNode;
4571     },
4572
4573     /**
4574      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4575      * @param {String/HTMLElement/Roo.Element} el The context element
4576      * @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'})
4577      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4578      * @return {HTMLElement/Roo.Element} The new node or Element
4579      */
4580     overwrite : function(el, values, returnElement){
4581         el = Roo.getDom(el);
4582         el.innerHTML = this.applyTemplate(values);
4583         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4584     }
4585 };
4586 /**
4587  * Alias for {@link #applyTemplate}
4588  * @method
4589  */
4590 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4591
4592 // backwards compat
4593 Roo.DomHelper.Template = Roo.Template;
4594
4595 /**
4596  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4597  * @param {String/HTMLElement} el A DOM element or its id
4598  * @returns {Roo.Template} The created template
4599  * @static
4600  */
4601 Roo.Template.from = function(el){
4602     el = Roo.getDom(el);
4603     return new Roo.Template(el.value || el.innerHTML);
4604 };/*
4605  * Based on:
4606  * Ext JS Library 1.1.1
4607  * Copyright(c) 2006-2007, Ext JS, LLC.
4608  *
4609  * Originally Released Under LGPL - original licence link has changed is not relivant.
4610  *
4611  * Fork - LGPL
4612  * <script type="text/javascript">
4613  */
4614  
4615
4616 /*
4617  * This is code is also distributed under MIT license for use
4618  * with jQuery and prototype JavaScript libraries.
4619  */
4620 /**
4621  * @class Roo.DomQuery
4622 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).
4623 <p>
4624 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>
4625
4626 <p>
4627 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.
4628 </p>
4629 <h4>Element Selectors:</h4>
4630 <ul class="list">
4631     <li> <b>*</b> any element</li>
4632     <li> <b>E</b> an element with the tag E</li>
4633     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4634     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4635     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4636     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4637 </ul>
4638 <h4>Attribute Selectors:</h4>
4639 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4640 <ul class="list">
4641     <li> <b>E[foo]</b> has an attribute "foo"</li>
4642     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4643     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4644     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4645     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4646     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4647     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4648 </ul>
4649 <h4>Pseudo Classes:</h4>
4650 <ul class="list">
4651     <li> <b>E:first-child</b> E is the first child of its parent</li>
4652     <li> <b>E:last-child</b> E is the last child of its parent</li>
4653     <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>
4654     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4655     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4656     <li> <b>E:only-child</b> E is the only child of its parent</li>
4657     <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>
4658     <li> <b>E:first</b> the first E in the resultset</li>
4659     <li> <b>E:last</b> the last E in the resultset</li>
4660     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4661     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4662     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4663     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4664     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4665     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4666     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4667     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4668     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4669 </ul>
4670 <h4>CSS Value Selectors:</h4>
4671 <ul class="list">
4672     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4673     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4674     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4675     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4676     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4677     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4678 </ul>
4679  * @singleton
4680  */
4681 Roo.DomQuery = function(){
4682     var cache = {}, simpleCache = {}, valueCache = {};
4683     var nonSpace = /\S/;
4684     var trimRe = /^\s+|\s+$/g;
4685     var tplRe = /\{(\d+)\}/g;
4686     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4687     var tagTokenRe = /^(#)?([\w-\*]+)/;
4688     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4689
4690     function child(p, index){
4691         var i = 0;
4692         var n = p.firstChild;
4693         while(n){
4694             if(n.nodeType == 1){
4695                if(++i == index){
4696                    return n;
4697                }
4698             }
4699             n = n.nextSibling;
4700         }
4701         return null;
4702     };
4703
4704     function next(n){
4705         while((n = n.nextSibling) && n.nodeType != 1);
4706         return n;
4707     };
4708
4709     function prev(n){
4710         while((n = n.previousSibling) && n.nodeType != 1);
4711         return n;
4712     };
4713
4714     function children(d){
4715         var n = d.firstChild, ni = -1;
4716             while(n){
4717                 var nx = n.nextSibling;
4718                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4719                     d.removeChild(n);
4720                 }else{
4721                     n.nodeIndex = ++ni;
4722                 }
4723                 n = nx;
4724             }
4725             return this;
4726         };
4727
4728     function byClassName(c, a, v){
4729         if(!v){
4730             return c;
4731         }
4732         var r = [], ri = -1, cn;
4733         for(var i = 0, ci; ci = c[i]; i++){
4734             if((' '+ci.className+' ').indexOf(v) != -1){
4735                 r[++ri] = ci;
4736             }
4737         }
4738         return r;
4739     };
4740
4741     function attrValue(n, attr){
4742         if(!n.tagName && typeof n.length != "undefined"){
4743             n = n[0];
4744         }
4745         if(!n){
4746             return null;
4747         }
4748         if(attr == "for"){
4749             return n.htmlFor;
4750         }
4751         if(attr == "class" || attr == "className"){
4752             return n.className;
4753         }
4754         return n.getAttribute(attr) || n[attr];
4755
4756     };
4757
4758     function getNodes(ns, mode, tagName){
4759         var result = [], ri = -1, cs;
4760         if(!ns){
4761             return result;
4762         }
4763         tagName = tagName || "*";
4764         if(typeof ns.getElementsByTagName != "undefined"){
4765             ns = [ns];
4766         }
4767         if(!mode){
4768             for(var i = 0, ni; ni = ns[i]; i++){
4769                 cs = ni.getElementsByTagName(tagName);
4770                 for(var j = 0, ci; ci = cs[j]; j++){
4771                     result[++ri] = ci;
4772                 }
4773             }
4774         }else if(mode == "/" || mode == ">"){
4775             var utag = tagName.toUpperCase();
4776             for(var i = 0, ni, cn; ni = ns[i]; i++){
4777                 cn = ni.children || ni.childNodes;
4778                 for(var j = 0, cj; cj = cn[j]; j++){
4779                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4780                         result[++ri] = cj;
4781                     }
4782                 }
4783             }
4784         }else if(mode == "+"){
4785             var utag = tagName.toUpperCase();
4786             for(var i = 0, n; n = ns[i]; i++){
4787                 while((n = n.nextSibling) && n.nodeType != 1);
4788                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4789                     result[++ri] = n;
4790                 }
4791             }
4792         }else if(mode == "~"){
4793             for(var i = 0, n; n = ns[i]; i++){
4794                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4795                 if(n){
4796                     result[++ri] = n;
4797                 }
4798             }
4799         }
4800         return result;
4801     };
4802
4803     function concat(a, b){
4804         if(b.slice){
4805             return a.concat(b);
4806         }
4807         for(var i = 0, l = b.length; i < l; i++){
4808             a[a.length] = b[i];
4809         }
4810         return a;
4811     }
4812
4813     function byTag(cs, tagName){
4814         if(cs.tagName || cs == document){
4815             cs = [cs];
4816         }
4817         if(!tagName){
4818             return cs;
4819         }
4820         var r = [], ri = -1;
4821         tagName = tagName.toLowerCase();
4822         for(var i = 0, ci; ci = cs[i]; i++){
4823             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4824                 r[++ri] = ci;
4825             }
4826         }
4827         return r;
4828     };
4829
4830     function byId(cs, attr, id){
4831         if(cs.tagName || cs == document){
4832             cs = [cs];
4833         }
4834         if(!id){
4835             return cs;
4836         }
4837         var r = [], ri = -1;
4838         for(var i = 0,ci; ci = cs[i]; i++){
4839             if(ci && ci.id == id){
4840                 r[++ri] = ci;
4841                 return r;
4842             }
4843         }
4844         return r;
4845     };
4846
4847     function byAttribute(cs, attr, value, op, custom){
4848         var r = [], ri = -1, st = custom=="{";
4849         var f = Roo.DomQuery.operators[op];
4850         for(var i = 0, ci; ci = cs[i]; i++){
4851             var a;
4852             if(st){
4853                 a = Roo.DomQuery.getStyle(ci, attr);
4854             }
4855             else if(attr == "class" || attr == "className"){
4856                 a = ci.className;
4857             }else if(attr == "for"){
4858                 a = ci.htmlFor;
4859             }else if(attr == "href"){
4860                 a = ci.getAttribute("href", 2);
4861             }else{
4862                 a = ci.getAttribute(attr);
4863             }
4864             if((f && f(a, value)) || (!f && a)){
4865                 r[++ri] = ci;
4866             }
4867         }
4868         return r;
4869     };
4870
4871     function byPseudo(cs, name, value){
4872         return Roo.DomQuery.pseudos[name](cs, value);
4873     };
4874
4875     // This is for IE MSXML which does not support expandos.
4876     // IE runs the same speed using setAttribute, however FF slows way down
4877     // and Safari completely fails so they need to continue to use expandos.
4878     var isIE = window.ActiveXObject ? true : false;
4879
4880     // this eval is stop the compressor from
4881     // renaming the variable to something shorter
4882     
4883     /** eval:var:batch */
4884     var batch = 30803; 
4885
4886     var key = 30803;
4887
4888     function nodupIEXml(cs){
4889         var d = ++key;
4890         cs[0].setAttribute("_nodup", d);
4891         var r = [cs[0]];
4892         for(var i = 1, len = cs.length; i < len; i++){
4893             var c = cs[i];
4894             if(!c.getAttribute("_nodup") != d){
4895                 c.setAttribute("_nodup", d);
4896                 r[r.length] = c;
4897             }
4898         }
4899         for(var i = 0, len = cs.length; i < len; i++){
4900             cs[i].removeAttribute("_nodup");
4901         }
4902         return r;
4903     }
4904
4905     function nodup(cs){
4906         if(!cs){
4907             return [];
4908         }
4909         var len = cs.length, c, i, r = cs, cj, ri = -1;
4910         if(!len || typeof cs.nodeType != "undefined" || len == 1){
4911             return cs;
4912         }
4913         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4914             return nodupIEXml(cs);
4915         }
4916         var d = ++key;
4917         cs[0]._nodup = d;
4918         for(i = 1; c = cs[i]; i++){
4919             if(c._nodup != d){
4920                 c._nodup = d;
4921             }else{
4922                 r = [];
4923                 for(var j = 0; j < i; j++){
4924                     r[++ri] = cs[j];
4925                 }
4926                 for(j = i+1; cj = cs[j]; j++){
4927                     if(cj._nodup != d){
4928                         cj._nodup = d;
4929                         r[++ri] = cj;
4930                     }
4931                 }
4932                 return r;
4933             }
4934         }
4935         return r;
4936     }
4937
4938     function quickDiffIEXml(c1, c2){
4939         var d = ++key;
4940         for(var i = 0, len = c1.length; i < len; i++){
4941             c1[i].setAttribute("_qdiff", d);
4942         }
4943         var r = [];
4944         for(var i = 0, len = c2.length; i < len; i++){
4945             if(c2[i].getAttribute("_qdiff") != d){
4946                 r[r.length] = c2[i];
4947             }
4948         }
4949         for(var i = 0, len = c1.length; i < len; i++){
4950            c1[i].removeAttribute("_qdiff");
4951         }
4952         return r;
4953     }
4954
4955     function quickDiff(c1, c2){
4956         var len1 = c1.length;
4957         if(!len1){
4958             return c2;
4959         }
4960         if(isIE && c1[0].selectSingleNode){
4961             return quickDiffIEXml(c1, c2);
4962         }
4963         var d = ++key;
4964         for(var i = 0; i < len1; i++){
4965             c1[i]._qdiff = d;
4966         }
4967         var r = [];
4968         for(var i = 0, len = c2.length; i < len; i++){
4969             if(c2[i]._qdiff != d){
4970                 r[r.length] = c2[i];
4971             }
4972         }
4973         return r;
4974     }
4975
4976     function quickId(ns, mode, root, id){
4977         if(ns == root){
4978            var d = root.ownerDocument || root;
4979            return d.getElementById(id);
4980         }
4981         ns = getNodes(ns, mode, "*");
4982         return byId(ns, null, id);
4983     }
4984
4985     return {
4986         getStyle : function(el, name){
4987             return Roo.fly(el).getStyle(name);
4988         },
4989         /**
4990          * Compiles a selector/xpath query into a reusable function. The returned function
4991          * takes one parameter "root" (optional), which is the context node from where the query should start.
4992          * @param {String} selector The selector/xpath query
4993          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4994          * @return {Function}
4995          */
4996         compile : function(path, type){
4997             type = type || "select";
4998             
4999             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5000             var q = path, mode, lq;
5001             var tk = Roo.DomQuery.matchers;
5002             var tklen = tk.length;
5003             var mm;
5004
5005             // accept leading mode switch
5006             var lmode = q.match(modeRe);
5007             if(lmode && lmode[1]){
5008                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5009                 q = q.replace(lmode[1], "");
5010             }
5011             // strip leading slashes
5012             while(path.substr(0, 1)=="/"){
5013                 path = path.substr(1);
5014             }
5015
5016             while(q && lq != q){
5017                 lq = q;
5018                 var tm = q.match(tagTokenRe);
5019                 if(type == "select"){
5020                     if(tm){
5021                         if(tm[1] == "#"){
5022                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5023                         }else{
5024                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5025                         }
5026                         q = q.replace(tm[0], "");
5027                     }else if(q.substr(0, 1) != '@'){
5028                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5029                     }
5030                 }else{
5031                     if(tm){
5032                         if(tm[1] == "#"){
5033                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5034                         }else{
5035                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5036                         }
5037                         q = q.replace(tm[0], "");
5038                     }
5039                 }
5040                 while(!(mm = q.match(modeRe))){
5041                     var matched = false;
5042                     for(var j = 0; j < tklen; j++){
5043                         var t = tk[j];
5044                         var m = q.match(t.re);
5045                         if(m){
5046                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5047                                                     return m[i];
5048                                                 });
5049                             q = q.replace(m[0], "");
5050                             matched = true;
5051                             break;
5052                         }
5053                     }
5054                     // prevent infinite loop on bad selector
5055                     if(!matched){
5056                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5057                     }
5058                 }
5059                 if(mm[1]){
5060                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5061                     q = q.replace(mm[1], "");
5062                 }
5063             }
5064             fn[fn.length] = "return nodup(n);\n}";
5065             
5066              /** 
5067               * list of variables that need from compression as they are used by eval.
5068              *  eval:var:batch 
5069              *  eval:var:nodup
5070              *  eval:var:byTag
5071              *  eval:var:ById
5072              *  eval:var:getNodes
5073              *  eval:var:quickId
5074              *  eval:var:mode
5075              *  eval:var:root
5076              *  eval:var:n
5077              *  eval:var:byClassName
5078              *  eval:var:byPseudo
5079              *  eval:var:byAttribute
5080              *  eval:var:attrValue
5081              * 
5082              **/ 
5083             eval(fn.join(""));
5084             return f;
5085         },
5086
5087         /**
5088          * Selects a group of elements.
5089          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5090          * @param {Node} root (optional) The start of the query (defaults to document).
5091          * @return {Array}
5092          */
5093         select : function(path, root, type){
5094             if(!root || root == document){
5095                 root = document;
5096             }
5097             if(typeof root == "string"){
5098                 root = document.getElementById(root);
5099             }
5100             var paths = path.split(",");
5101             var results = [];
5102             for(var i = 0, len = paths.length; i < len; i++){
5103                 var p = paths[i].replace(trimRe, "");
5104                 if(!cache[p]){
5105                     cache[p] = Roo.DomQuery.compile(p);
5106                     if(!cache[p]){
5107                         throw p + " is not a valid selector";
5108                     }
5109                 }
5110                 var result = cache[p](root);
5111                 if(result && result != document){
5112                     results = results.concat(result);
5113                 }
5114             }
5115             if(paths.length > 1){
5116                 return nodup(results);
5117             }
5118             return results;
5119         },
5120
5121         /**
5122          * Selects a single element.
5123          * @param {String} selector The selector/xpath query
5124          * @param {Node} root (optional) The start of the query (defaults to document).
5125          * @return {Element}
5126          */
5127         selectNode : function(path, root){
5128             return Roo.DomQuery.select(path, root)[0];
5129         },
5130
5131         /**
5132          * Selects the value of a node, optionally replacing null with the defaultValue.
5133          * @param {String} selector The selector/xpath query
5134          * @param {Node} root (optional) The start of the query (defaults to document).
5135          * @param {String} defaultValue
5136          */
5137         selectValue : function(path, root, defaultValue){
5138             path = path.replace(trimRe, "");
5139             if(!valueCache[path]){
5140                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5141             }
5142             var n = valueCache[path](root);
5143             n = n[0] ? n[0] : n;
5144             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5145             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5146         },
5147
5148         /**
5149          * Selects the value of a node, parsing integers and floats.
5150          * @param {String} selector The selector/xpath query
5151          * @param {Node} root (optional) The start of the query (defaults to document).
5152          * @param {Number} defaultValue
5153          * @return {Number}
5154          */
5155         selectNumber : function(path, root, defaultValue){
5156             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5157             return parseFloat(v);
5158         },
5159
5160         /**
5161          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5162          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5163          * @param {String} selector The simple selector to test
5164          * @return {Boolean}
5165          */
5166         is : function(el, ss){
5167             if(typeof el == "string"){
5168                 el = document.getElementById(el);
5169             }
5170             var isArray = (el instanceof Array);
5171             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5172             return isArray ? (result.length == el.length) : (result.length > 0);
5173         },
5174
5175         /**
5176          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5177          * @param {Array} el An array of elements to filter
5178          * @param {String} selector The simple selector to test
5179          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5180          * the selector instead of the ones that match
5181          * @return {Array}
5182          */
5183         filter : function(els, ss, nonMatches){
5184             ss = ss.replace(trimRe, "");
5185             if(!simpleCache[ss]){
5186                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5187             }
5188             var result = simpleCache[ss](els);
5189             return nonMatches ? quickDiff(result, els) : result;
5190         },
5191
5192         /**
5193          * Collection of matching regular expressions and code snippets.
5194          */
5195         matchers : [{
5196                 re: /^\.([\w-]+)/,
5197                 select: 'n = byClassName(n, null, " {1} ");'
5198             }, {
5199                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5200                 select: 'n = byPseudo(n, "{1}", "{2}");'
5201             },{
5202                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5203                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5204             }, {
5205                 re: /^#([\w-]+)/,
5206                 select: 'n = byId(n, null, "{1}");'
5207             },{
5208                 re: /^@([\w-]+)/,
5209                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5210             }
5211         ],
5212
5213         /**
5214          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5215          * 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;.
5216          */
5217         operators : {
5218             "=" : function(a, v){
5219                 return a == v;
5220             },
5221             "!=" : function(a, v){
5222                 return a != v;
5223             },
5224             "^=" : function(a, v){
5225                 return a && a.substr(0, v.length) == v;
5226             },
5227             "$=" : function(a, v){
5228                 return a && a.substr(a.length-v.length) == v;
5229             },
5230             "*=" : function(a, v){
5231                 return a && a.indexOf(v) !== -1;
5232             },
5233             "%=" : function(a, v){
5234                 return (a % v) == 0;
5235             },
5236             "|=" : function(a, v){
5237                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5238             },
5239             "~=" : function(a, v){
5240                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5241             }
5242         },
5243
5244         /**
5245          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5246          * and the argument (if any) supplied in the selector.
5247          */
5248         pseudos : {
5249             "first-child" : function(c){
5250                 var r = [], ri = -1, n;
5251                 for(var i = 0, ci; ci = n = c[i]; i++){
5252                     while((n = n.previousSibling) && n.nodeType != 1);
5253                     if(!n){
5254                         r[++ri] = ci;
5255                     }
5256                 }
5257                 return r;
5258             },
5259
5260             "last-child" : function(c){
5261                 var r = [], ri = -1, n;
5262                 for(var i = 0, ci; ci = n = c[i]; i++){
5263                     while((n = n.nextSibling) && n.nodeType != 1);
5264                     if(!n){
5265                         r[++ri] = ci;
5266                     }
5267                 }
5268                 return r;
5269             },
5270
5271             "nth-child" : function(c, a) {
5272                 var r = [], ri = -1;
5273                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5274                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5275                 for(var i = 0, n; n = c[i]; i++){
5276                     var pn = n.parentNode;
5277                     if (batch != pn._batch) {
5278                         var j = 0;
5279                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5280                             if(cn.nodeType == 1){
5281                                cn.nodeIndex = ++j;
5282                             }
5283                         }
5284                         pn._batch = batch;
5285                     }
5286                     if (f == 1) {
5287                         if (l == 0 || n.nodeIndex == l){
5288                             r[++ri] = n;
5289                         }
5290                     } else if ((n.nodeIndex + l) % f == 0){
5291                         r[++ri] = n;
5292                     }
5293                 }
5294
5295                 return r;
5296             },
5297
5298             "only-child" : function(c){
5299                 var r = [], ri = -1;;
5300                 for(var i = 0, ci; ci = c[i]; i++){
5301                     if(!prev(ci) && !next(ci)){
5302                         r[++ri] = ci;
5303                     }
5304                 }
5305                 return r;
5306             },
5307
5308             "empty" : function(c){
5309                 var r = [], ri = -1;
5310                 for(var i = 0, ci; ci = c[i]; i++){
5311                     var cns = ci.childNodes, j = 0, cn, empty = true;
5312                     while(cn = cns[j]){
5313                         ++j;
5314                         if(cn.nodeType == 1 || cn.nodeType == 3){
5315                             empty = false;
5316                             break;
5317                         }
5318                     }
5319                     if(empty){
5320                         r[++ri] = ci;
5321                     }
5322                 }
5323                 return r;
5324             },
5325
5326             "contains" : function(c, v){
5327                 var r = [], ri = -1;
5328                 for(var i = 0, ci; ci = c[i]; i++){
5329                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5330                         r[++ri] = ci;
5331                     }
5332                 }
5333                 return r;
5334             },
5335
5336             "nodeValue" : function(c, v){
5337                 var r = [], ri = -1;
5338                 for(var i = 0, ci; ci = c[i]; i++){
5339                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5340                         r[++ri] = ci;
5341                     }
5342                 }
5343                 return r;
5344             },
5345
5346             "checked" : function(c){
5347                 var r = [], ri = -1;
5348                 for(var i = 0, ci; ci = c[i]; i++){
5349                     if(ci.checked == true){
5350                         r[++ri] = ci;
5351                     }
5352                 }
5353                 return r;
5354             },
5355
5356             "not" : function(c, ss){
5357                 return Roo.DomQuery.filter(c, ss, true);
5358             },
5359
5360             "odd" : function(c){
5361                 return this["nth-child"](c, "odd");
5362             },
5363
5364             "even" : function(c){
5365                 return this["nth-child"](c, "even");
5366             },
5367
5368             "nth" : function(c, a){
5369                 return c[a-1] || [];
5370             },
5371
5372             "first" : function(c){
5373                 return c[0] || [];
5374             },
5375
5376             "last" : function(c){
5377                 return c[c.length-1] || [];
5378             },
5379
5380             "has" : function(c, ss){
5381                 var s = Roo.DomQuery.select;
5382                 var r = [], ri = -1;
5383                 for(var i = 0, ci; ci = c[i]; i++){
5384                     if(s(ss, ci).length > 0){
5385                         r[++ri] = ci;
5386                     }
5387                 }
5388                 return r;
5389             },
5390
5391             "next" : function(c, ss){
5392                 var is = Roo.DomQuery.is;
5393                 var r = [], ri = -1;
5394                 for(var i = 0, ci; ci = c[i]; i++){
5395                     var n = next(ci);
5396                     if(n && is(n, ss)){
5397                         r[++ri] = ci;
5398                     }
5399                 }
5400                 return r;
5401             },
5402
5403             "prev" : function(c, ss){
5404                 var is = Roo.DomQuery.is;
5405                 var r = [], ri = -1;
5406                 for(var i = 0, ci; ci = c[i]; i++){
5407                     var n = prev(ci);
5408                     if(n && is(n, ss)){
5409                         r[++ri] = ci;
5410                     }
5411                 }
5412                 return r;
5413             }
5414         }
5415     };
5416 }();
5417
5418 /**
5419  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5420  * @param {String} path The selector/xpath query
5421  * @param {Node} root (optional) The start of the query (defaults to document).
5422  * @return {Array}
5423  * @member Roo
5424  * @method query
5425  */
5426 Roo.query = Roo.DomQuery.select;
5427 /*
5428  * Based on:
5429  * Ext JS Library 1.1.1
5430  * Copyright(c) 2006-2007, Ext JS, LLC.
5431  *
5432  * Originally Released Under LGPL - original licence link has changed is not relivant.
5433  *
5434  * Fork - LGPL
5435  * <script type="text/javascript">
5436  */
5437
5438 /**
5439  * @class Roo.util.Observable
5440  * Base class that provides a common interface for publishing events. Subclasses are expected to
5441  * to have a property "events" with all the events defined.<br>
5442  * For example:
5443  * <pre><code>
5444  Employee = function(name){
5445     this.name = name;
5446     this.addEvents({
5447         "fired" : true,
5448         "quit" : true
5449     });
5450  }
5451  Roo.extend(Employee, Roo.util.Observable);
5452 </code></pre>
5453  * @param {Object} config properties to use (incuding events / listeners)
5454  */
5455
5456 Roo.util.Observable = function(cfg){
5457     
5458     cfg = cfg|| {};
5459     this.addEvents(cfg.events || {});
5460     if (cfg.events) {
5461         delete cfg.events; // make sure
5462     }
5463      
5464     Roo.apply(this, cfg);
5465     
5466     if(this.listeners){
5467         this.on(this.listeners);
5468         delete this.listeners;
5469     }
5470 };
5471 Roo.util.Observable.prototype = {
5472     /** 
5473  * @cfg {Object} listeners  list of events and functions to call for this object, 
5474  * For example :
5475  * <pre><code>
5476     listeners :  { 
5477        'click' : function(e) {
5478            ..... 
5479         } ,
5480         .... 
5481     } 
5482   </code></pre>
5483  */
5484     
5485     
5486     /**
5487      * Fires the specified event with the passed parameters (minus the event name).
5488      * @param {String} eventName
5489      * @param {Object...} args Variable number of parameters are passed to handlers
5490      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5491      */
5492     fireEvent : function(){
5493         var ce = this.events[arguments[0].toLowerCase()];
5494         if(typeof ce == "object"){
5495             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5496         }else{
5497             return true;
5498         }
5499     },
5500
5501     // private
5502     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5503
5504     /**
5505      * Appends an event handler to this component
5506      * @param {String}   eventName The type of event to listen for
5507      * @param {Function} handler The method the event invokes
5508      * @param {Object}   scope (optional) The scope in which to execute the handler
5509      * function. The handler function's "this" context.
5510      * @param {Object}   options (optional) An object containing handler configuration
5511      * properties. This may contain any of the following properties:<ul>
5512      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5513      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5514      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5515      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5516      * by the specified number of milliseconds. If the event fires again within that time, the original
5517      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5518      * </ul><br>
5519      * <p>
5520      * <b>Combining Options</b><br>
5521      * Using the options argument, it is possible to combine different types of listeners:<br>
5522      * <br>
5523      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5524                 <pre><code>
5525                 el.on('click', this.onClick, this, {
5526                         single: true,
5527                 delay: 100,
5528                 forumId: 4
5529                 });
5530                 </code></pre>
5531      * <p>
5532      * <b>Attaching multiple handlers in 1 call</b><br>
5533      * The method also allows for a single argument to be passed which is a config object containing properties
5534      * which specify multiple handlers.
5535      * <pre><code>
5536                 el.on({
5537                         'click': {
5538                         fn: this.onClick,
5539                         scope: this,
5540                         delay: 100
5541                 }, 
5542                 'mouseover': {
5543                         fn: this.onMouseOver,
5544                         scope: this
5545                 },
5546                 'mouseout': {
5547                         fn: this.onMouseOut,
5548                         scope: this
5549                 }
5550                 });
5551                 </code></pre>
5552      * <p>
5553      * Or a shorthand syntax which passes the same scope object to all handlers:
5554         <pre><code>
5555                 el.on({
5556                         'click': this.onClick,
5557                 'mouseover': this.onMouseOver,
5558                 'mouseout': this.onMouseOut,
5559                 scope: this
5560                 });
5561                 </code></pre>
5562      */
5563     addListener : function(eventName, fn, scope, o){
5564         if(typeof eventName == "object"){
5565             o = eventName;
5566             for(var e in o){
5567                 if(this.filterOptRe.test(e)){
5568                     continue;
5569                 }
5570                 if(typeof o[e] == "function"){
5571                     // shared options
5572                     this.addListener(e, o[e], o.scope,  o);
5573                 }else{
5574                     // individual options
5575                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5576                 }
5577             }
5578             return;
5579         }
5580         o = (!o || typeof o == "boolean") ? {} : o;
5581         eventName = eventName.toLowerCase();
5582         var ce = this.events[eventName] || true;
5583         if(typeof ce == "boolean"){
5584             ce = new Roo.util.Event(this, eventName);
5585             this.events[eventName] = ce;
5586         }
5587         ce.addListener(fn, scope, o);
5588     },
5589
5590     /**
5591      * Removes a listener
5592      * @param {String}   eventName     The type of event to listen for
5593      * @param {Function} handler        The handler to remove
5594      * @param {Object}   scope  (optional) The scope (this object) for the handler
5595      */
5596     removeListener : function(eventName, fn, scope){
5597         var ce = this.events[eventName.toLowerCase()];
5598         if(typeof ce == "object"){
5599             ce.removeListener(fn, scope);
5600         }
5601     },
5602
5603     /**
5604      * Removes all listeners for this object
5605      */
5606     purgeListeners : function(){
5607         for(var evt in this.events){
5608             if(typeof this.events[evt] == "object"){
5609                  this.events[evt].clearListeners();
5610             }
5611         }
5612     },
5613
5614     relayEvents : function(o, events){
5615         var createHandler = function(ename){
5616             return function(){
5617                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5618             };
5619         };
5620         for(var i = 0, len = events.length; i < len; i++){
5621             var ename = events[i];
5622             if(!this.events[ename]){ this.events[ename] = true; };
5623             o.on(ename, createHandler(ename), this);
5624         }
5625     },
5626
5627     /**
5628      * Used to define events on this Observable
5629      * @param {Object} object The object with the events defined
5630      */
5631     addEvents : function(o){
5632         if(!this.events){
5633             this.events = {};
5634         }
5635         Roo.applyIf(this.events, o);
5636     },
5637
5638     /**
5639      * Checks to see if this object has any listeners for a specified event
5640      * @param {String} eventName The name of the event to check for
5641      * @return {Boolean} True if the event is being listened for, else false
5642      */
5643     hasListener : function(eventName){
5644         var e = this.events[eventName];
5645         return typeof e == "object" && e.listeners.length > 0;
5646     }
5647 };
5648 /**
5649  * Appends an event handler to this element (shorthand for addListener)
5650  * @param {String}   eventName     The type of event to listen for
5651  * @param {Function} handler        The method the event invokes
5652  * @param {Object}   scope (optional) The scope in which to execute the handler
5653  * function. The handler function's "this" context.
5654  * @param {Object}   options  (optional)
5655  * @method
5656  */
5657 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5658 /**
5659  * Removes a listener (shorthand for removeListener)
5660  * @param {String}   eventName     The type of event to listen for
5661  * @param {Function} handler        The handler to remove
5662  * @param {Object}   scope  (optional) The scope (this object) for the handler
5663  * @method
5664  */
5665 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5666
5667 /**
5668  * Starts capture on the specified Observable. All events will be passed
5669  * to the supplied function with the event name + standard signature of the event
5670  * <b>before</b> the event is fired. If the supplied function returns false,
5671  * the event will not fire.
5672  * @param {Observable} o The Observable to capture
5673  * @param {Function} fn The function to call
5674  * @param {Object} scope (optional) The scope (this object) for the fn
5675  * @static
5676  */
5677 Roo.util.Observable.capture = function(o, fn, scope){
5678     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5679 };
5680
5681 /**
5682  * Removes <b>all</b> added captures from the Observable.
5683  * @param {Observable} o The Observable to release
5684  * @static
5685  */
5686 Roo.util.Observable.releaseCapture = function(o){
5687     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5688 };
5689
5690 (function(){
5691
5692     var createBuffered = function(h, o, scope){
5693         var task = new Roo.util.DelayedTask();
5694         return function(){
5695             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5696         };
5697     };
5698
5699     var createSingle = function(h, e, fn, scope){
5700         return function(){
5701             e.removeListener(fn, scope);
5702             return h.apply(scope, arguments);
5703         };
5704     };
5705
5706     var createDelayed = function(h, o, scope){
5707         return function(){
5708             var args = Array.prototype.slice.call(arguments, 0);
5709             setTimeout(function(){
5710                 h.apply(scope, args);
5711             }, o.delay || 10);
5712         };
5713     };
5714
5715     Roo.util.Event = function(obj, name){
5716         this.name = name;
5717         this.obj = obj;
5718         this.listeners = [];
5719     };
5720
5721     Roo.util.Event.prototype = {
5722         addListener : function(fn, scope, options){
5723             var o = options || {};
5724             scope = scope || this.obj;
5725             if(!this.isListening(fn, scope)){
5726                 var l = {fn: fn, scope: scope, options: o};
5727                 var h = fn;
5728                 if(o.delay){
5729                     h = createDelayed(h, o, scope);
5730                 }
5731                 if(o.single){
5732                     h = createSingle(h, this, fn, scope);
5733                 }
5734                 if(o.buffer){
5735                     h = createBuffered(h, o, scope);
5736                 }
5737                 l.fireFn = h;
5738                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5739                     this.listeners.push(l);
5740                 }else{
5741                     this.listeners = this.listeners.slice(0);
5742                     this.listeners.push(l);
5743                 }
5744             }
5745         },
5746
5747         findListener : function(fn, scope){
5748             scope = scope || this.obj;
5749             var ls = this.listeners;
5750             for(var i = 0, len = ls.length; i < len; i++){
5751                 var l = ls[i];
5752                 if(l.fn == fn && l.scope == scope){
5753                     return i;
5754                 }
5755             }
5756             return -1;
5757         },
5758
5759         isListening : function(fn, scope){
5760             return this.findListener(fn, scope) != -1;
5761         },
5762
5763         removeListener : function(fn, scope){
5764             var index;
5765             if((index = this.findListener(fn, scope)) != -1){
5766                 if(!this.firing){
5767                     this.listeners.splice(index, 1);
5768                 }else{
5769                     this.listeners = this.listeners.slice(0);
5770                     this.listeners.splice(index, 1);
5771                 }
5772                 return true;
5773             }
5774             return false;
5775         },
5776
5777         clearListeners : function(){
5778             this.listeners = [];
5779         },
5780
5781         fire : function(){
5782             var ls = this.listeners, scope, len = ls.length;
5783             if(len > 0){
5784                 this.firing = true;
5785                 var args = Array.prototype.slice.call(arguments, 0);
5786                 for(var i = 0; i < len; i++){
5787                     var l = ls[i];
5788                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5789                         this.firing = false;
5790                         return false;
5791                     }
5792                 }
5793                 this.firing = false;
5794             }
5795             return true;
5796         }
5797     };
5798 })();/*
5799  * Based on:
5800  * Ext JS Library 1.1.1
5801  * Copyright(c) 2006-2007, Ext JS, LLC.
5802  *
5803  * Originally Released Under LGPL - original licence link has changed is not relivant.
5804  *
5805  * Fork - LGPL
5806  * <script type="text/javascript">
5807  */
5808
5809 /**
5810  * @class Roo.EventManager
5811  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5812  * several useful events directly.
5813  * See {@link Roo.EventObject} for more details on normalized event objects.
5814  * @singleton
5815  */
5816 Roo.EventManager = function(){
5817     var docReadyEvent, docReadyProcId, docReadyState = false;
5818     var resizeEvent, resizeTask, textEvent, textSize;
5819     var E = Roo.lib.Event;
5820     var D = Roo.lib.Dom;
5821
5822
5823     var fireDocReady = function(){
5824         if(!docReadyState){
5825             docReadyState = true;
5826             Roo.isReady = true;
5827             if(docReadyProcId){
5828                 clearInterval(docReadyProcId);
5829             }
5830             if(Roo.isGecko || Roo.isOpera) {
5831                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5832             }
5833             if(Roo.isIE){
5834                 var defer = document.getElementById("ie-deferred-loader");
5835                 if(defer){
5836                     defer.onreadystatechange = null;
5837                     defer.parentNode.removeChild(defer);
5838                 }
5839             }
5840             if(docReadyEvent){
5841                 docReadyEvent.fire();
5842                 docReadyEvent.clearListeners();
5843             }
5844         }
5845     };
5846     
5847     var initDocReady = function(){
5848         docReadyEvent = new Roo.util.Event();
5849         if(Roo.isGecko || Roo.isOpera) {
5850             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5851         }else if(Roo.isIE){
5852             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5853             var defer = document.getElementById("ie-deferred-loader");
5854             defer.onreadystatechange = function(){
5855                 if(this.readyState == "complete"){
5856                     fireDocReady();
5857                 }
5858             };
5859         }else if(Roo.isSafari){ 
5860             docReadyProcId = setInterval(function(){
5861                 var rs = document.readyState;
5862                 if(rs == "complete") {
5863                     fireDocReady();     
5864                  }
5865             }, 10);
5866         }
5867         // no matter what, make sure it fires on load
5868         E.on(window, "load", fireDocReady);
5869     };
5870
5871     var createBuffered = function(h, o){
5872         var task = new Roo.util.DelayedTask(h);
5873         return function(e){
5874             // create new event object impl so new events don't wipe out properties
5875             e = new Roo.EventObjectImpl(e);
5876             task.delay(o.buffer, h, null, [e]);
5877         };
5878     };
5879
5880     var createSingle = function(h, el, ename, fn){
5881         return function(e){
5882             Roo.EventManager.removeListener(el, ename, fn);
5883             h(e);
5884         };
5885     };
5886
5887     var createDelayed = function(h, o){
5888         return function(e){
5889             // create new event object impl so new events don't wipe out properties
5890             e = new Roo.EventObjectImpl(e);
5891             setTimeout(function(){
5892                 h(e);
5893             }, o.delay || 10);
5894         };
5895     };
5896
5897     var listen = function(element, ename, opt, fn, scope){
5898         var o = (!opt || typeof opt == "boolean") ? {} : opt;
5899         fn = fn || o.fn; scope = scope || o.scope;
5900         var el = Roo.getDom(element);
5901         if(!el){
5902             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5903         }
5904         var h = function(e){
5905             e = Roo.EventObject.setEvent(e);
5906             var t;
5907             if(o.delegate){
5908                 t = e.getTarget(o.delegate, el);
5909                 if(!t){
5910                     return;
5911                 }
5912             }else{
5913                 t = e.target;
5914             }
5915             if(o.stopEvent === true){
5916                 e.stopEvent();
5917             }
5918             if(o.preventDefault === true){
5919                e.preventDefault();
5920             }
5921             if(o.stopPropagation === true){
5922                 e.stopPropagation();
5923             }
5924
5925             if(o.normalized === false){
5926                 e = e.browserEvent;
5927             }
5928
5929             fn.call(scope || el, e, t, o);
5930         };
5931         if(o.delay){
5932             h = createDelayed(h, o);
5933         }
5934         if(o.single){
5935             h = createSingle(h, el, ename, fn);
5936         }
5937         if(o.buffer){
5938             h = createBuffered(h, o);
5939         }
5940         fn._handlers = fn._handlers || [];
5941         fn._handlers.push([Roo.id(el), ename, h]);
5942
5943         E.on(el, ename, h);
5944         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5945             el.addEventListener("DOMMouseScroll", h, false);
5946             E.on(window, 'unload', function(){
5947                 el.removeEventListener("DOMMouseScroll", h, false);
5948             });
5949         }
5950         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5951             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5952         }
5953         return h;
5954     };
5955
5956     var stopListening = function(el, ename, fn){
5957         var id = Roo.id(el), hds = fn._handlers, hd = fn;
5958         if(hds){
5959             for(var i = 0, len = hds.length; i < len; i++){
5960                 var h = hds[i];
5961                 if(h[0] == id && h[1] == ename){
5962                     hd = h[2];
5963                     hds.splice(i, 1);
5964                     break;
5965                 }
5966             }
5967         }
5968         E.un(el, ename, hd);
5969         el = Roo.getDom(el);
5970         if(ename == "mousewheel" && el.addEventListener){
5971             el.removeEventListener("DOMMouseScroll", hd, false);
5972         }
5973         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5974             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5975         }
5976     };
5977
5978     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5979     
5980     var pub = {
5981         
5982         
5983         /** 
5984          * Fix for doc tools
5985          * @scope Roo.EventManager
5986          */
5987         
5988         
5989         /** 
5990          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5991          * object with a Roo.EventObject
5992          * @param {Function} fn        The method the event invokes
5993          * @param {Object}   scope    An object that becomes the scope of the handler
5994          * @param {boolean}  override If true, the obj passed in becomes
5995          *                             the execution scope of the listener
5996          * @return {Function} The wrapped function
5997          * @deprecated
5998          */
5999         wrap : function(fn, scope, override){
6000             return function(e){
6001                 Roo.EventObject.setEvent(e);
6002                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6003             };
6004         },
6005         
6006         /**
6007      * Appends an event handler to an element (shorthand for addListener)
6008      * @param {String/HTMLElement}   element        The html element or id to assign the
6009      * @param {String}   eventName The type of event to listen for
6010      * @param {Function} handler The method the event invokes
6011      * @param {Object}   scope (optional) The scope in which to execute the handler
6012      * function. The handler function's "this" context.
6013      * @param {Object}   options (optional) An object containing handler configuration
6014      * properties. This may contain any of the following properties:<ul>
6015      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6016      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6017      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6018      * <li>preventDefault {Boolean} True to prevent the default action</li>
6019      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6020      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6021      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6022      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6023      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6024      * by the specified number of milliseconds. If the event fires again within that time, the original
6025      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6026      * </ul><br>
6027      * <p>
6028      * <b>Combining Options</b><br>
6029      * Using the options argument, it is possible to combine different types of listeners:<br>
6030      * <br>
6031      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6032      * Code:<pre><code>
6033 el.on('click', this.onClick, this, {
6034     single: true,
6035     delay: 100,
6036     stopEvent : true,
6037     forumId: 4
6038 });</code></pre>
6039      * <p>
6040      * <b>Attaching multiple handlers in 1 call</b><br>
6041       * The method also allows for a single argument to be passed which is a config object containing properties
6042      * which specify multiple handlers.
6043      * <p>
6044      * Code:<pre><code>
6045 el.on({
6046     'click' : {
6047         fn: this.onClick
6048         scope: this,
6049         delay: 100
6050     },
6051     'mouseover' : {
6052         fn: this.onMouseOver
6053         scope: this
6054     },
6055     'mouseout' : {
6056         fn: this.onMouseOut
6057         scope: this
6058     }
6059 });</code></pre>
6060      * <p>
6061      * Or a shorthand syntax:<br>
6062      * Code:<pre><code>
6063 el.on({
6064     'click' : this.onClick,
6065     'mouseover' : this.onMouseOver,
6066     'mouseout' : this.onMouseOut
6067     scope: this
6068 });</code></pre>
6069      */
6070         addListener : function(element, eventName, fn, scope, options){
6071             if(typeof eventName == "object"){
6072                 var o = eventName;
6073                 for(var e in o){
6074                     if(propRe.test(e)){
6075                         continue;
6076                     }
6077                     if(typeof o[e] == "function"){
6078                         // shared options
6079                         listen(element, e, o, o[e], o.scope);
6080                     }else{
6081                         // individual options
6082                         listen(element, e, o[e]);
6083                     }
6084                 }
6085                 return;
6086             }
6087             return listen(element, eventName, options, fn, scope);
6088         },
6089         
6090         /**
6091          * Removes an event handler
6092          *
6093          * @param {String/HTMLElement}   element        The id or html element to remove the 
6094          *                             event from
6095          * @param {String}   eventName     The type of event
6096          * @param {Function} fn
6097          * @return {Boolean} True if a listener was actually removed
6098          */
6099         removeListener : function(element, eventName, fn){
6100             return stopListening(element, eventName, fn);
6101         },
6102         
6103         /**
6104          * Fires when the document is ready (before onload and before images are loaded). Can be 
6105          * accessed shorthanded Roo.onReady().
6106          * @param {Function} fn        The method the event invokes
6107          * @param {Object}   scope    An  object that becomes the scope of the handler
6108          * @param {boolean}  options
6109          */
6110         onDocumentReady : function(fn, scope, options){
6111             if(docReadyState){ // if it already fired
6112                 docReadyEvent.addListener(fn, scope, options);
6113                 docReadyEvent.fire();
6114                 docReadyEvent.clearListeners();
6115                 return;
6116             }
6117             if(!docReadyEvent){
6118                 initDocReady();
6119             }
6120             docReadyEvent.addListener(fn, scope, options);
6121         },
6122         
6123         /**
6124          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6125          * @param {Function} fn        The method the event invokes
6126          * @param {Object}   scope    An object that becomes the scope of the handler
6127          * @param {boolean}  options
6128          */
6129         onWindowResize : function(fn, scope, options){
6130             if(!resizeEvent){
6131                 resizeEvent = new Roo.util.Event();
6132                 resizeTask = new Roo.util.DelayedTask(function(){
6133                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6134                 });
6135                 E.on(window, "resize", function(){
6136                     if(Roo.isIE){
6137                         resizeTask.delay(50);
6138                     }else{
6139                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6140                     }
6141                 });
6142             }
6143             resizeEvent.addListener(fn, scope, options);
6144         },
6145
6146         /**
6147          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6148          * @param {Function} fn        The method the event invokes
6149          * @param {Object}   scope    An object that becomes the scope of the handler
6150          * @param {boolean}  options
6151          */
6152         onTextResize : function(fn, scope, options){
6153             if(!textEvent){
6154                 textEvent = new Roo.util.Event();
6155                 var textEl = new Roo.Element(document.createElement('div'));
6156                 textEl.dom.className = 'x-text-resize';
6157                 textEl.dom.innerHTML = 'X';
6158                 textEl.appendTo(document.body);
6159                 textSize = textEl.dom.offsetHeight;
6160                 setInterval(function(){
6161                     if(textEl.dom.offsetHeight != textSize){
6162                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6163                     }
6164                 }, this.textResizeInterval);
6165             }
6166             textEvent.addListener(fn, scope, options);
6167         },
6168
6169         /**
6170          * Removes the passed window resize listener.
6171          * @param {Function} fn        The method the event invokes
6172          * @param {Object}   scope    The scope of handler
6173          */
6174         removeResizeListener : function(fn, scope){
6175             if(resizeEvent){
6176                 resizeEvent.removeListener(fn, scope);
6177             }
6178         },
6179
6180         // private
6181         fireResize : function(){
6182             if(resizeEvent){
6183                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6184             }   
6185         },
6186         /**
6187          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6188          */
6189         ieDeferSrc : false,
6190         /**
6191          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6192          */
6193         textResizeInterval : 50
6194     };
6195     
6196     /**
6197      * Fix for doc tools
6198      * @scopeAlias pub=Roo.EventManager
6199      */
6200     
6201      /**
6202      * Appends an event handler to an element (shorthand for addListener)
6203      * @param {String/HTMLElement}   element        The html element or id to assign the
6204      * @param {String}   eventName The type of event to listen for
6205      * @param {Function} handler The method the event invokes
6206      * @param {Object}   scope (optional) The scope in which to execute the handler
6207      * function. The handler function's "this" context.
6208      * @param {Object}   options (optional) An object containing handler configuration
6209      * properties. This may contain any of the following properties:<ul>
6210      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6211      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6212      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6213      * <li>preventDefault {Boolean} True to prevent the default action</li>
6214      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6215      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6216      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6217      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6218      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6219      * by the specified number of milliseconds. If the event fires again within that time, the original
6220      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6221      * </ul><br>
6222      * <p>
6223      * <b>Combining Options</b><br>
6224      * Using the options argument, it is possible to combine different types of listeners:<br>
6225      * <br>
6226      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6227      * Code:<pre><code>
6228 el.on('click', this.onClick, this, {
6229     single: true,
6230     delay: 100,
6231     stopEvent : true,
6232     forumId: 4
6233 });</code></pre>
6234      * <p>
6235      * <b>Attaching multiple handlers in 1 call</b><br>
6236       * The method also allows for a single argument to be passed which is a config object containing properties
6237      * which specify multiple handlers.
6238      * <p>
6239      * Code:<pre><code>
6240 el.on({
6241     'click' : {
6242         fn: this.onClick
6243         scope: this,
6244         delay: 100
6245     },
6246     'mouseover' : {
6247         fn: this.onMouseOver
6248         scope: this
6249     },
6250     'mouseout' : {
6251         fn: this.onMouseOut
6252         scope: this
6253     }
6254 });</code></pre>
6255      * <p>
6256      * Or a shorthand syntax:<br>
6257      * Code:<pre><code>
6258 el.on({
6259     'click' : this.onClick,
6260     'mouseover' : this.onMouseOver,
6261     'mouseout' : this.onMouseOut
6262     scope: this
6263 });</code></pre>
6264      */
6265     pub.on = pub.addListener;
6266     pub.un = pub.removeListener;
6267
6268     pub.stoppedMouseDownEvent = new Roo.util.Event();
6269     return pub;
6270 }();
6271 /**
6272   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6273   * @param {Function} fn        The method the event invokes
6274   * @param {Object}   scope    An  object that becomes the scope of the handler
6275   * @param {boolean}  override If true, the obj passed in becomes
6276   *                             the execution scope of the listener
6277   * @member Roo
6278   * @method onReady
6279  */
6280 Roo.onReady = Roo.EventManager.onDocumentReady;
6281
6282 Roo.onReady(function(){
6283     var bd = Roo.get(document.body);
6284     if(!bd){ return; }
6285
6286     var cls = [
6287             Roo.isIE ? "roo-ie"
6288             : Roo.isGecko ? "roo-gecko"
6289             : Roo.isOpera ? "roo-opera"
6290             : Roo.isSafari ? "roo-safari" : ""];
6291
6292     if(Roo.isMac){
6293         cls.push("roo-mac");
6294     }
6295     if(Roo.isLinux){
6296         cls.push("roo-linux");
6297     }
6298     if(Roo.isBorderBox){
6299         cls.push('roo-border-box');
6300     }
6301     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6302         var p = bd.dom.parentNode;
6303         if(p){
6304             p.className += ' roo-strict';
6305         }
6306     }
6307     bd.addClass(cls.join(' '));
6308 });
6309
6310 /**
6311  * @class Roo.EventObject
6312  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6313  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6314  * Example:
6315  * <pre><code>
6316  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6317     e.preventDefault();
6318     var target = e.getTarget();
6319     ...
6320  }
6321  var myDiv = Roo.get("myDiv");
6322  myDiv.on("click", handleClick);
6323  //or
6324  Roo.EventManager.on("myDiv", 'click', handleClick);
6325  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6326  </code></pre>
6327  * @singleton
6328  */
6329 Roo.EventObject = function(){
6330     
6331     var E = Roo.lib.Event;
6332     
6333     // safari keypress events for special keys return bad keycodes
6334     var safariKeys = {
6335         63234 : 37, // left
6336         63235 : 39, // right
6337         63232 : 38, // up
6338         63233 : 40, // down
6339         63276 : 33, // page up
6340         63277 : 34, // page down
6341         63272 : 46, // delete
6342         63273 : 36, // home
6343         63275 : 35  // end
6344     };
6345
6346     // normalize button clicks
6347     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6348                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6349
6350     Roo.EventObjectImpl = function(e){
6351         if(e){
6352             this.setEvent(e.browserEvent || e);
6353         }
6354     };
6355     Roo.EventObjectImpl.prototype = {
6356         /**
6357          * Used to fix doc tools.
6358          * @scope Roo.EventObject.prototype
6359          */
6360             
6361
6362         
6363         
6364         /** The normal browser event */
6365         browserEvent : null,
6366         /** The button pressed in a mouse event */
6367         button : -1,
6368         /** True if the shift key was down during the event */
6369         shiftKey : false,
6370         /** True if the control key was down during the event */
6371         ctrlKey : false,
6372         /** True if the alt key was down during the event */
6373         altKey : false,
6374
6375         /** Key constant 
6376         * @type Number */
6377         BACKSPACE : 8,
6378         /** Key constant 
6379         * @type Number */
6380         TAB : 9,
6381         /** Key constant 
6382         * @type Number */
6383         RETURN : 13,
6384         /** Key constant 
6385         * @type Number */
6386         ENTER : 13,
6387         /** Key constant 
6388         * @type Number */
6389         SHIFT : 16,
6390         /** Key constant 
6391         * @type Number */
6392         CONTROL : 17,
6393         /** Key constant 
6394         * @type Number */
6395         ESC : 27,
6396         /** Key constant 
6397         * @type Number */
6398         SPACE : 32,
6399         /** Key constant 
6400         * @type Number */
6401         PAGEUP : 33,
6402         /** Key constant 
6403         * @type Number */
6404         PAGEDOWN : 34,
6405         /** Key constant 
6406         * @type Number */
6407         END : 35,
6408         /** Key constant 
6409         * @type Number */
6410         HOME : 36,
6411         /** Key constant 
6412         * @type Number */
6413         LEFT : 37,
6414         /** Key constant 
6415         * @type Number */
6416         UP : 38,
6417         /** Key constant 
6418         * @type Number */
6419         RIGHT : 39,
6420         /** Key constant 
6421         * @type Number */
6422         DOWN : 40,
6423         /** Key constant 
6424         * @type Number */
6425         DELETE : 46,
6426         /** Key constant 
6427         * @type Number */
6428         F5 : 116,
6429
6430            /** @private */
6431         setEvent : function(e){
6432             if(e == this || (e && e.browserEvent)){ // already wrapped
6433                 return e;
6434             }
6435             this.browserEvent = e;
6436             if(e){
6437                 // normalize buttons
6438                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6439                 if(e.type == 'click' && this.button == -1){
6440                     this.button = 0;
6441                 }
6442                 this.type = e.type;
6443                 this.shiftKey = e.shiftKey;
6444                 // mac metaKey behaves like ctrlKey
6445                 this.ctrlKey = e.ctrlKey || e.metaKey;
6446                 this.altKey = e.altKey;
6447                 // in getKey these will be normalized for the mac
6448                 this.keyCode = e.keyCode;
6449                 // keyup warnings on firefox.
6450                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6451                 // cache the target for the delayed and or buffered events
6452                 this.target = E.getTarget(e);
6453                 // same for XY
6454                 this.xy = E.getXY(e);
6455             }else{
6456                 this.button = -1;
6457                 this.shiftKey = false;
6458                 this.ctrlKey = false;
6459                 this.altKey = false;
6460                 this.keyCode = 0;
6461                 this.charCode =0;
6462                 this.target = null;
6463                 this.xy = [0, 0];
6464             }
6465             return this;
6466         },
6467
6468         /**
6469          * Stop the event (preventDefault and stopPropagation)
6470          */
6471         stopEvent : function(){
6472             if(this.browserEvent){
6473                 if(this.browserEvent.type == 'mousedown'){
6474                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6475                 }
6476                 E.stopEvent(this.browserEvent);
6477             }
6478         },
6479
6480         /**
6481          * Prevents the browsers default handling of the event.
6482          */
6483         preventDefault : function(){
6484             if(this.browserEvent){
6485                 E.preventDefault(this.browserEvent);
6486             }
6487         },
6488
6489         /** @private */
6490         isNavKeyPress : function(){
6491             var k = this.keyCode;
6492             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6493             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6494         },
6495
6496         isSpecialKey : function(){
6497             var k = this.keyCode;
6498             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6499             (k == 16) || (k == 17) ||
6500             (k >= 18 && k <= 20) ||
6501             (k >= 33 && k <= 35) ||
6502             (k >= 36 && k <= 39) ||
6503             (k >= 44 && k <= 45);
6504         },
6505         /**
6506          * Cancels bubbling of the event.
6507          */
6508         stopPropagation : function(){
6509             if(this.browserEvent){
6510                 if(this.type == 'mousedown'){
6511                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6512                 }
6513                 E.stopPropagation(this.browserEvent);
6514             }
6515         },
6516
6517         /**
6518          * Gets the key code for the event.
6519          * @return {Number}
6520          */
6521         getCharCode : function(){
6522             return this.charCode || this.keyCode;
6523         },
6524
6525         /**
6526          * Returns a normalized keyCode for the event.
6527          * @return {Number} The key code
6528          */
6529         getKey : function(){
6530             var k = this.keyCode || this.charCode;
6531             return Roo.isSafari ? (safariKeys[k] || k) : k;
6532         },
6533
6534         /**
6535          * Gets the x coordinate of the event.
6536          * @return {Number}
6537          */
6538         getPageX : function(){
6539             return this.xy[0];
6540         },
6541
6542         /**
6543          * Gets the y coordinate of the event.
6544          * @return {Number}
6545          */
6546         getPageY : function(){
6547             return this.xy[1];
6548         },
6549
6550         /**
6551          * Gets the time of the event.
6552          * @return {Number}
6553          */
6554         getTime : function(){
6555             if(this.browserEvent){
6556                 return E.getTime(this.browserEvent);
6557             }
6558             return null;
6559         },
6560
6561         /**
6562          * Gets the page coordinates of the event.
6563          * @return {Array} The xy values like [x, y]
6564          */
6565         getXY : function(){
6566             return this.xy;
6567         },
6568
6569         /**
6570          * Gets the target for the event.
6571          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6572          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6573                 search as a number or element (defaults to 10 || document.body)
6574          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6575          * @return {HTMLelement}
6576          */
6577         getTarget : function(selector, maxDepth, returnEl){
6578             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6579         },
6580         /**
6581          * Gets the related target.
6582          * @return {HTMLElement}
6583          */
6584         getRelatedTarget : function(){
6585             if(this.browserEvent){
6586                 return E.getRelatedTarget(this.browserEvent);
6587             }
6588             return null;
6589         },
6590
6591         /**
6592          * Normalizes mouse wheel delta across browsers
6593          * @return {Number} The delta
6594          */
6595         getWheelDelta : function(){
6596             var e = this.browserEvent;
6597             var delta = 0;
6598             if(e.wheelDelta){ /* IE/Opera. */
6599                 delta = e.wheelDelta/120;
6600             }else if(e.detail){ /* Mozilla case. */
6601                 delta = -e.detail/3;
6602             }
6603             return delta;
6604         },
6605
6606         /**
6607          * Returns true if the control, meta, shift or alt key was pressed during this event.
6608          * @return {Boolean}
6609          */
6610         hasModifier : function(){
6611             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6612         },
6613
6614         /**
6615          * Returns true if the target of this event equals el or is a child of el
6616          * @param {String/HTMLElement/Element} el
6617          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6618          * @return {Boolean}
6619          */
6620         within : function(el, related){
6621             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6622             return t && Roo.fly(el).contains(t);
6623         },
6624
6625         getPoint : function(){
6626             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6627         }
6628     };
6629
6630     return new Roo.EventObjectImpl();
6631 }();
6632             
6633     /*
6634  * Based on:
6635  * Ext JS Library 1.1.1
6636  * Copyright(c) 2006-2007, Ext JS, LLC.
6637  *
6638  * Originally Released Under LGPL - original licence link has changed is not relivant.
6639  *
6640  * Fork - LGPL
6641  * <script type="text/javascript">
6642  */
6643
6644  
6645 // was in Composite Element!??!?!
6646  
6647 (function(){
6648     var D = Roo.lib.Dom;
6649     var E = Roo.lib.Event;
6650     var A = Roo.lib.Anim;
6651
6652     // local style camelizing for speed
6653     var propCache = {};
6654     var camelRe = /(-[a-z])/gi;
6655     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6656     var view = document.defaultView;
6657
6658 /**
6659  * @class Roo.Element
6660  * Represents an Element in the DOM.<br><br>
6661  * Usage:<br>
6662 <pre><code>
6663 var el = Roo.get("my-div");
6664
6665 // or with getEl
6666 var el = getEl("my-div");
6667
6668 // or with a DOM element
6669 var el = Roo.get(myDivElement);
6670 </code></pre>
6671  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6672  * each call instead of constructing a new one.<br><br>
6673  * <b>Animations</b><br />
6674  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6675  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6676 <pre>
6677 Option    Default   Description
6678 --------- --------  ---------------------------------------------
6679 duration  .35       The duration of the animation in seconds
6680 easing    easeOut   The YUI easing method
6681 callback  none      A function to execute when the anim completes
6682 scope     this      The scope (this) of the callback function
6683 </pre>
6684 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6685 * manipulate the animation. Here's an example:
6686 <pre><code>
6687 var el = Roo.get("my-div");
6688
6689 // no animation
6690 el.setWidth(100);
6691
6692 // default animation
6693 el.setWidth(100, true);
6694
6695 // animation with some options set
6696 el.setWidth(100, {
6697     duration: 1,
6698     callback: this.foo,
6699     scope: this
6700 });
6701
6702 // using the "anim" property to get the Anim object
6703 var opt = {
6704     duration: 1,
6705     callback: this.foo,
6706     scope: this
6707 };
6708 el.setWidth(100, opt);
6709 ...
6710 if(opt.anim.isAnimated()){
6711     opt.anim.stop();
6712 }
6713 </code></pre>
6714 * <b> Composite (Collections of) Elements</b><br />
6715  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6716  * @constructor Create a new Element directly.
6717  * @param {String/HTMLElement} element
6718  * @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).
6719  */
6720     Roo.Element = function(element, forceNew){
6721         var dom = typeof element == "string" ?
6722                 document.getElementById(element) : element;
6723         if(!dom){ // invalid id/element
6724             return null;
6725         }
6726         var id = dom.id;
6727         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6728             return Roo.Element.cache[id];
6729         }
6730
6731         /**
6732          * The DOM element
6733          * @type HTMLElement
6734          */
6735         this.dom = dom;
6736
6737         /**
6738          * The DOM element ID
6739          * @type String
6740          */
6741         this.id = id || Roo.id(dom);
6742     };
6743
6744     var El = Roo.Element;
6745
6746     El.prototype = {
6747         /**
6748          * The element's default display mode  (defaults to "")
6749          * @type String
6750          */
6751         originalDisplay : "",
6752
6753         visibilityMode : 1,
6754         /**
6755          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6756          * @type String
6757          */
6758         defaultUnit : "px",
6759         /**
6760          * Sets the element's visibility mode. When setVisible() is called it
6761          * will use this to determine whether to set the visibility or the display property.
6762          * @param visMode Element.VISIBILITY or Element.DISPLAY
6763          * @return {Roo.Element} this
6764          */
6765         setVisibilityMode : function(visMode){
6766             this.visibilityMode = visMode;
6767             return this;
6768         },
6769         /**
6770          * Convenience method for setVisibilityMode(Element.DISPLAY)
6771          * @param {String} display (optional) What to set display to when visible
6772          * @return {Roo.Element} this
6773          */
6774         enableDisplayMode : function(display){
6775             this.setVisibilityMode(El.DISPLAY);
6776             if(typeof display != "undefined") this.originalDisplay = display;
6777             return this;
6778         },
6779
6780         /**
6781          * 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)
6782          * @param {String} selector The simple selector to test
6783          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6784                 search as a number or element (defaults to 10 || document.body)
6785          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6786          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6787          */
6788         findParent : function(simpleSelector, maxDepth, returnEl){
6789             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6790             maxDepth = maxDepth || 50;
6791             if(typeof maxDepth != "number"){
6792                 stopEl = Roo.getDom(maxDepth);
6793                 maxDepth = 10;
6794             }
6795             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6796                 if(dq.is(p, simpleSelector)){
6797                     return returnEl ? Roo.get(p) : p;
6798                 }
6799                 depth++;
6800                 p = p.parentNode;
6801             }
6802             return null;
6803         },
6804
6805
6806         /**
6807          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6808          * @param {String} selector The simple selector to test
6809          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6810                 search as a number or element (defaults to 10 || document.body)
6811          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6812          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6813          */
6814         findParentNode : function(simpleSelector, maxDepth, returnEl){
6815             var p = Roo.fly(this.dom.parentNode, '_internal');
6816             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6817         },
6818
6819         /**
6820          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6821          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6822          * @param {String} selector The simple selector to test
6823          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6824                 search as a number or element (defaults to 10 || document.body)
6825          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6826          */
6827         up : function(simpleSelector, maxDepth){
6828             return this.findParentNode(simpleSelector, maxDepth, true);
6829         },
6830
6831
6832
6833         /**
6834          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6835          * @param {String} selector The simple selector to test
6836          * @return {Boolean} True if this element matches the selector, else false
6837          */
6838         is : function(simpleSelector){
6839             return Roo.DomQuery.is(this.dom, simpleSelector);
6840         },
6841
6842         /**
6843          * Perform animation on this element.
6844          * @param {Object} args The YUI animation control args
6845          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6846          * @param {Function} onComplete (optional) Function to call when animation completes
6847          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6848          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6849          * @return {Roo.Element} this
6850          */
6851         animate : function(args, duration, onComplete, easing, animType){
6852             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6853             return this;
6854         },
6855
6856         /*
6857          * @private Internal animation call
6858          */
6859         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6860             animType = animType || 'run';
6861             opt = opt || {};
6862             var anim = Roo.lib.Anim[animType](
6863                 this.dom, args,
6864                 (opt.duration || defaultDur) || .35,
6865                 (opt.easing || defaultEase) || 'easeOut',
6866                 function(){
6867                     Roo.callback(cb, this);
6868                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6869                 },
6870                 this
6871             );
6872             opt.anim = anim;
6873             return anim;
6874         },
6875
6876         // private legacy anim prep
6877         preanim : function(a, i){
6878             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6879         },
6880
6881         /**
6882          * Removes worthless text nodes
6883          * @param {Boolean} forceReclean (optional) By default the element
6884          * keeps track if it has been cleaned already so
6885          * you can call this over and over. However, if you update the element and
6886          * need to force a reclean, you can pass true.
6887          */
6888         clean : function(forceReclean){
6889             if(this.isCleaned && forceReclean !== true){
6890                 return this;
6891             }
6892             var ns = /\S/;
6893             var d = this.dom, n = d.firstChild, ni = -1;
6894             while(n){
6895                 var nx = n.nextSibling;
6896                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6897                     d.removeChild(n);
6898                 }else{
6899                     n.nodeIndex = ++ni;
6900                 }
6901                 n = nx;
6902             }
6903             this.isCleaned = true;
6904             return this;
6905         },
6906
6907         // private
6908         calcOffsetsTo : function(el){
6909             el = Roo.get(el);
6910             var d = el.dom;
6911             var restorePos = false;
6912             if(el.getStyle('position') == 'static'){
6913                 el.position('relative');
6914                 restorePos = true;
6915             }
6916             var x = 0, y =0;
6917             var op = this.dom;
6918             while(op && op != d && op.tagName != 'HTML'){
6919                 x+= op.offsetLeft;
6920                 y+= op.offsetTop;
6921                 op = op.offsetParent;
6922             }
6923             if(restorePos){
6924                 el.position('static');
6925             }
6926             return [x, y];
6927         },
6928
6929         /**
6930          * Scrolls this element into view within the passed container.
6931          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6932          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6933          * @return {Roo.Element} this
6934          */
6935         scrollIntoView : function(container, hscroll){
6936             var c = Roo.getDom(container) || document.body;
6937             var el = this.dom;
6938
6939             var o = this.calcOffsetsTo(c),
6940                 l = o[0],
6941                 t = o[1],
6942                 b = t+el.offsetHeight,
6943                 r = l+el.offsetWidth;
6944
6945             var ch = c.clientHeight;
6946             var ct = parseInt(c.scrollTop, 10);
6947             var cl = parseInt(c.scrollLeft, 10);
6948             var cb = ct + ch;
6949             var cr = cl + c.clientWidth;
6950
6951             if(t < ct){
6952                 c.scrollTop = t;
6953             }else if(b > cb){
6954                 c.scrollTop = b-ch;
6955             }
6956
6957             if(hscroll !== false){
6958                 if(l < cl){
6959                     c.scrollLeft = l;
6960                 }else if(r > cr){
6961                     c.scrollLeft = r-c.clientWidth;
6962                 }
6963             }
6964             return this;
6965         },
6966
6967         // private
6968         scrollChildIntoView : function(child, hscroll){
6969             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6970         },
6971
6972         /**
6973          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6974          * the new height may not be available immediately.
6975          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6976          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6977          * @param {Function} onComplete (optional) Function to call when animation completes
6978          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6979          * @return {Roo.Element} this
6980          */
6981         autoHeight : function(animate, duration, onComplete, easing){
6982             var oldHeight = this.getHeight();
6983             this.clip();
6984             this.setHeight(1); // force clipping
6985             setTimeout(function(){
6986                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6987                 if(!animate){
6988                     this.setHeight(height);
6989                     this.unclip();
6990                     if(typeof onComplete == "function"){
6991                         onComplete();
6992                     }
6993                 }else{
6994                     this.setHeight(oldHeight); // restore original height
6995                     this.setHeight(height, animate, duration, function(){
6996                         this.unclip();
6997                         if(typeof onComplete == "function") onComplete();
6998                     }.createDelegate(this), easing);
6999                 }
7000             }.createDelegate(this), 0);
7001             return this;
7002         },
7003
7004         /**
7005          * Returns true if this element is an ancestor of the passed element
7006          * @param {HTMLElement/String} el The element to check
7007          * @return {Boolean} True if this element is an ancestor of el, else false
7008          */
7009         contains : function(el){
7010             if(!el){return false;}
7011             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7012         },
7013
7014         /**
7015          * Checks whether the element is currently visible using both visibility and display properties.
7016          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7017          * @return {Boolean} True if the element is currently visible, else false
7018          */
7019         isVisible : function(deep) {
7020             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7021             if(deep !== true || !vis){
7022                 return vis;
7023             }
7024             var p = this.dom.parentNode;
7025             while(p && p.tagName.toLowerCase() != "body"){
7026                 if(!Roo.fly(p, '_isVisible').isVisible()){
7027                     return false;
7028                 }
7029                 p = p.parentNode;
7030             }
7031             return true;
7032         },
7033
7034         /**
7035          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7036          * @param {String} selector The CSS selector
7037          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7038          * @return {CompositeElement/CompositeElementLite} The composite element
7039          */
7040         select : function(selector, unique){
7041             return El.select(selector, unique, this.dom);
7042         },
7043
7044         /**
7045          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7046          * @param {String} selector The CSS selector
7047          * @return {Array} An array of the matched nodes
7048          */
7049         query : function(selector, unique){
7050             return Roo.DomQuery.select(selector, this.dom);
7051         },
7052
7053         /**
7054          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7055          * @param {String} selector The CSS selector
7056          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7057          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7058          */
7059         child : function(selector, returnDom){
7060             var n = Roo.DomQuery.selectNode(selector, this.dom);
7061             return returnDom ? n : Roo.get(n);
7062         },
7063
7064         /**
7065          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7066          * @param {String} selector The CSS selector
7067          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7068          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7069          */
7070         down : function(selector, returnDom){
7071             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7072             return returnDom ? n : Roo.get(n);
7073         },
7074
7075         /**
7076          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7077          * @param {String} group The group the DD object is member of
7078          * @param {Object} config The DD config object
7079          * @param {Object} overrides An object containing methods to override/implement on the DD object
7080          * @return {Roo.dd.DD} The DD object
7081          */
7082         initDD : function(group, config, overrides){
7083             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7084             return Roo.apply(dd, overrides);
7085         },
7086
7087         /**
7088          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7089          * @param {String} group The group the DDProxy object is member of
7090          * @param {Object} config The DDProxy config object
7091          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7092          * @return {Roo.dd.DDProxy} The DDProxy object
7093          */
7094         initDDProxy : function(group, config, overrides){
7095             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7096             return Roo.apply(dd, overrides);
7097         },
7098
7099         /**
7100          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7101          * @param {String} group The group the DDTarget object is member of
7102          * @param {Object} config The DDTarget config object
7103          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7104          * @return {Roo.dd.DDTarget} The DDTarget object
7105          */
7106         initDDTarget : function(group, config, overrides){
7107             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7108             return Roo.apply(dd, overrides);
7109         },
7110
7111         /**
7112          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7113          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7114          * @param {Boolean} visible Whether the element is visible
7115          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7116          * @return {Roo.Element} this
7117          */
7118          setVisible : function(visible, animate){
7119             if(!animate || !A){
7120                 if(this.visibilityMode == El.DISPLAY){
7121                     this.setDisplayed(visible);
7122                 }else{
7123                     this.fixDisplay();
7124                     this.dom.style.visibility = visible ? "visible" : "hidden";
7125                 }
7126             }else{
7127                 // closure for composites
7128                 var dom = this.dom;
7129                 var visMode = this.visibilityMode;
7130                 if(visible){
7131                     this.setOpacity(.01);
7132                     this.setVisible(true);
7133                 }
7134                 this.anim({opacity: { to: (visible?1:0) }},
7135                       this.preanim(arguments, 1),
7136                       null, .35, 'easeIn', function(){
7137                          if(!visible){
7138                              if(visMode == El.DISPLAY){
7139                                  dom.style.display = "none";
7140                              }else{
7141                                  dom.style.visibility = "hidden";
7142                              }
7143                              Roo.get(dom).setOpacity(1);
7144                          }
7145                      });
7146             }
7147             return this;
7148         },
7149
7150         /**
7151          * Returns true if display is not "none"
7152          * @return {Boolean}
7153          */
7154         isDisplayed : function() {
7155             return this.getStyle("display") != "none";
7156         },
7157
7158         /**
7159          * Toggles the element's visibility or display, depending on visibility mode.
7160          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7161          * @return {Roo.Element} this
7162          */
7163         toggle : function(animate){
7164             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7165             return this;
7166         },
7167
7168         /**
7169          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7170          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7171          * @return {Roo.Element} this
7172          */
7173         setDisplayed : function(value) {
7174             if(typeof value == "boolean"){
7175                value = value ? this.originalDisplay : "none";
7176             }
7177             this.setStyle("display", value);
7178             return this;
7179         },
7180
7181         /**
7182          * Tries to focus the element. Any exceptions are caught and ignored.
7183          * @return {Roo.Element} this
7184          */
7185         focus : function() {
7186             try{
7187                 this.dom.focus();
7188             }catch(e){}
7189             return this;
7190         },
7191
7192         /**
7193          * Tries to blur the element. Any exceptions are caught and ignored.
7194          * @return {Roo.Element} this
7195          */
7196         blur : function() {
7197             try{
7198                 this.dom.blur();
7199             }catch(e){}
7200             return this;
7201         },
7202
7203         /**
7204          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7205          * @param {String/Array} className The CSS class to add, or an array of classes
7206          * @return {Roo.Element} this
7207          */
7208         addClass : function(className){
7209             if(className instanceof Array){
7210                 for(var i = 0, len = className.length; i < len; i++) {
7211                     this.addClass(className[i]);
7212                 }
7213             }else{
7214                 if(className && !this.hasClass(className)){
7215                     this.dom.className = this.dom.className + " " + className;
7216                 }
7217             }
7218             return this;
7219         },
7220
7221         /**
7222          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7223          * @param {String/Array} className The CSS class to add, or an array of classes
7224          * @return {Roo.Element} this
7225          */
7226         radioClass : function(className){
7227             var siblings = this.dom.parentNode.childNodes;
7228             for(var i = 0; i < siblings.length; i++) {
7229                 var s = siblings[i];
7230                 if(s.nodeType == 1){
7231                     Roo.get(s).removeClass(className);
7232                 }
7233             }
7234             this.addClass(className);
7235             return this;
7236         },
7237
7238         /**
7239          * Removes one or more CSS classes from the element.
7240          * @param {String/Array} className The CSS class to remove, or an array of classes
7241          * @return {Roo.Element} this
7242          */
7243         removeClass : function(className){
7244             if(!className || !this.dom.className){
7245                 return this;
7246             }
7247             if(className instanceof Array){
7248                 for(var i = 0, len = className.length; i < len; i++) {
7249                     this.removeClass(className[i]);
7250                 }
7251             }else{
7252                 if(this.hasClass(className)){
7253                     var re = this.classReCache[className];
7254                     if (!re) {
7255                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7256                        this.classReCache[className] = re;
7257                     }
7258                     this.dom.className =
7259                         this.dom.className.replace(re, " ");
7260                 }
7261             }
7262             return this;
7263         },
7264
7265         // private
7266         classReCache: {},
7267
7268         /**
7269          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7270          * @param {String} className The CSS class to toggle
7271          * @return {Roo.Element} this
7272          */
7273         toggleClass : function(className){
7274             if(this.hasClass(className)){
7275                 this.removeClass(className);
7276             }else{
7277                 this.addClass(className);
7278             }
7279             return this;
7280         },
7281
7282         /**
7283          * Checks if the specified CSS class exists on this element's DOM node.
7284          * @param {String} className The CSS class to check for
7285          * @return {Boolean} True if the class exists, else false
7286          */
7287         hasClass : function(className){
7288             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7289         },
7290
7291         /**
7292          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7293          * @param {String} oldClassName The CSS class to replace
7294          * @param {String} newClassName The replacement CSS class
7295          * @return {Roo.Element} this
7296          */
7297         replaceClass : function(oldClassName, newClassName){
7298             this.removeClass(oldClassName);
7299             this.addClass(newClassName);
7300             return this;
7301         },
7302
7303         /**
7304          * Returns an object with properties matching the styles requested.
7305          * For example, el.getStyles('color', 'font-size', 'width') might return
7306          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7307          * @param {String} style1 A style name
7308          * @param {String} style2 A style name
7309          * @param {String} etc.
7310          * @return {Object} The style object
7311          */
7312         getStyles : function(){
7313             var a = arguments, len = a.length, r = {};
7314             for(var i = 0; i < len; i++){
7315                 r[a[i]] = this.getStyle(a[i]);
7316             }
7317             return r;
7318         },
7319
7320         /**
7321          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7322          * @param {String} property The style property whose value is returned.
7323          * @return {String} The current value of the style property for this element.
7324          */
7325         getStyle : function(){
7326             return view && view.getComputedStyle ?
7327                 function(prop){
7328                     var el = this.dom, v, cs, camel;
7329                     if(prop == 'float'){
7330                         prop = "cssFloat";
7331                     }
7332                     if(el.style && (v = el.style[prop])){
7333                         return v;
7334                     }
7335                     if(cs = view.getComputedStyle(el, "")){
7336                         if(!(camel = propCache[prop])){
7337                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7338                         }
7339                         return cs[camel];
7340                     }
7341                     return null;
7342                 } :
7343                 function(prop){
7344                     var el = this.dom, v, cs, camel;
7345                     if(prop == 'opacity'){
7346                         if(typeof el.style.filter == 'string'){
7347                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7348                             if(m){
7349                                 var fv = parseFloat(m[1]);
7350                                 if(!isNaN(fv)){
7351                                     return fv ? fv / 100 : 0;
7352                                 }
7353                             }
7354                         }
7355                         return 1;
7356                     }else if(prop == 'float'){
7357                         prop = "styleFloat";
7358                     }
7359                     if(!(camel = propCache[prop])){
7360                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7361                     }
7362                     if(v = el.style[camel]){
7363                         return v;
7364                     }
7365                     if(cs = el.currentStyle){
7366                         return cs[camel];
7367                     }
7368                     return null;
7369                 };
7370         }(),
7371
7372         /**
7373          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7374          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7375          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7376          * @return {Roo.Element} this
7377          */
7378         setStyle : function(prop, value){
7379             if(typeof prop == "string"){
7380                 var camel;
7381                 if(!(camel = propCache[prop])){
7382                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7383                 }
7384                 if(camel == 'opacity') {
7385                     this.setOpacity(value);
7386                 }else{
7387                     this.dom.style[camel] = value;
7388                 }
7389             }else{
7390                 for(var style in prop){
7391                     if(typeof prop[style] != "function"){
7392                        this.setStyle(style, prop[style]);
7393                     }
7394                 }
7395             }
7396             return this;
7397         },
7398
7399         /**
7400          * More flexible version of {@link #setStyle} for setting style properties.
7401          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7402          * a function which returns such a specification.
7403          * @return {Roo.Element} this
7404          */
7405         applyStyles : function(style){
7406             Roo.DomHelper.applyStyles(this.dom, style);
7407             return this;
7408         },
7409
7410         /**
7411           * 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).
7412           * @return {Number} The X position of the element
7413           */
7414         getX : function(){
7415             return D.getX(this.dom);
7416         },
7417
7418         /**
7419           * 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).
7420           * @return {Number} The Y position of the element
7421           */
7422         getY : function(){
7423             return D.getY(this.dom);
7424         },
7425
7426         /**
7427           * 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).
7428           * @return {Array} The XY position of the element
7429           */
7430         getXY : function(){
7431             return D.getXY(this.dom);
7432         },
7433
7434         /**
7435          * 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).
7436          * @param {Number} The X position of the element
7437          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7438          * @return {Roo.Element} this
7439          */
7440         setX : function(x, animate){
7441             if(!animate || !A){
7442                 D.setX(this.dom, x);
7443             }else{
7444                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7445             }
7446             return this;
7447         },
7448
7449         /**
7450          * 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).
7451          * @param {Number} The Y position of the element
7452          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7453          * @return {Roo.Element} this
7454          */
7455         setY : function(y, animate){
7456             if(!animate || !A){
7457                 D.setY(this.dom, y);
7458             }else{
7459                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7460             }
7461             return this;
7462         },
7463
7464         /**
7465          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7466          * @param {String} left The left CSS property value
7467          * @return {Roo.Element} this
7468          */
7469         setLeft : function(left){
7470             this.setStyle("left", this.addUnits(left));
7471             return this;
7472         },
7473
7474         /**
7475          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7476          * @param {String} top The top CSS property value
7477          * @return {Roo.Element} this
7478          */
7479         setTop : function(top){
7480             this.setStyle("top", this.addUnits(top));
7481             return this;
7482         },
7483
7484         /**
7485          * Sets the element's CSS right style.
7486          * @param {String} right The right CSS property value
7487          * @return {Roo.Element} this
7488          */
7489         setRight : function(right){
7490             this.setStyle("right", this.addUnits(right));
7491             return this;
7492         },
7493
7494         /**
7495          * Sets the element's CSS bottom style.
7496          * @param {String} bottom The bottom CSS property value
7497          * @return {Roo.Element} this
7498          */
7499         setBottom : function(bottom){
7500             this.setStyle("bottom", this.addUnits(bottom));
7501             return this;
7502         },
7503
7504         /**
7505          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7506          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7507          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7508          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7509          * @return {Roo.Element} this
7510          */
7511         setXY : function(pos, animate){
7512             if(!animate || !A){
7513                 D.setXY(this.dom, pos);
7514             }else{
7515                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7516             }
7517             return this;
7518         },
7519
7520         /**
7521          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7522          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7523          * @param {Number} x X value for new position (coordinates are page-based)
7524          * @param {Number} y Y value for new position (coordinates are page-based)
7525          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7526          * @return {Roo.Element} this
7527          */
7528         setLocation : function(x, y, animate){
7529             this.setXY([x, y], this.preanim(arguments, 2));
7530             return this;
7531         },
7532
7533         /**
7534          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7535          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7536          * @param {Number} x X value for new position (coordinates are page-based)
7537          * @param {Number} y Y value for new position (coordinates are page-based)
7538          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7539          * @return {Roo.Element} this
7540          */
7541         moveTo : function(x, y, animate){
7542             this.setXY([x, y], this.preanim(arguments, 2));
7543             return this;
7544         },
7545
7546         /**
7547          * Returns the region of the given element.
7548          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7549          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7550          */
7551         getRegion : function(){
7552             return D.getRegion(this.dom);
7553         },
7554
7555         /**
7556          * Returns the offset height of the element
7557          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7558          * @return {Number} The element's height
7559          */
7560         getHeight : function(contentHeight){
7561             var h = this.dom.offsetHeight || 0;
7562             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7563         },
7564
7565         /**
7566          * Returns the offset width of the element
7567          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7568          * @return {Number} The element's width
7569          */
7570         getWidth : function(contentWidth){
7571             var w = this.dom.offsetWidth || 0;
7572             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7573         },
7574
7575         /**
7576          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7577          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7578          * if a height has not been set using CSS.
7579          * @return {Number}
7580          */
7581         getComputedHeight : function(){
7582             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7583             if(!h){
7584                 h = parseInt(this.getStyle('height'), 10) || 0;
7585                 if(!this.isBorderBox()){
7586                     h += this.getFrameWidth('tb');
7587                 }
7588             }
7589             return h;
7590         },
7591
7592         /**
7593          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7594          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7595          * if a width has not been set using CSS.
7596          * @return {Number}
7597          */
7598         getComputedWidth : function(){
7599             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7600             if(!w){
7601                 w = parseInt(this.getStyle('width'), 10) || 0;
7602                 if(!this.isBorderBox()){
7603                     w += this.getFrameWidth('lr');
7604                 }
7605             }
7606             return w;
7607         },
7608
7609         /**
7610          * Returns the size of the element.
7611          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7612          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7613          */
7614         getSize : function(contentSize){
7615             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7616         },
7617
7618         /**
7619          * Returns the width and height of the viewport.
7620          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7621          */
7622         getViewSize : function(){
7623             var d = this.dom, doc = document, aw = 0, ah = 0;
7624             if(d == doc || d == doc.body){
7625                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7626             }else{
7627                 return {
7628                     width : d.clientWidth,
7629                     height: d.clientHeight
7630                 };
7631             }
7632         },
7633
7634         /**
7635          * Returns the value of the "value" attribute
7636          * @param {Boolean} asNumber true to parse the value as a number
7637          * @return {String/Number}
7638          */
7639         getValue : function(asNumber){
7640             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7641         },
7642
7643         // private
7644         adjustWidth : function(width){
7645             if(typeof width == "number"){
7646                 if(this.autoBoxAdjust && !this.isBorderBox()){
7647                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7648                 }
7649                 if(width < 0){
7650                     width = 0;
7651                 }
7652             }
7653             return width;
7654         },
7655
7656         // private
7657         adjustHeight : function(height){
7658             if(typeof height == "number"){
7659                if(this.autoBoxAdjust && !this.isBorderBox()){
7660                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7661                }
7662                if(height < 0){
7663                    height = 0;
7664                }
7665             }
7666             return height;
7667         },
7668
7669         /**
7670          * Set the width of the element
7671          * @param {Number} width The new width
7672          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7673          * @return {Roo.Element} this
7674          */
7675         setWidth : function(width, animate){
7676             width = this.adjustWidth(width);
7677             if(!animate || !A){
7678                 this.dom.style.width = this.addUnits(width);
7679             }else{
7680                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7681             }
7682             return this;
7683         },
7684
7685         /**
7686          * Set the height of the element
7687          * @param {Number} height The new height
7688          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7689          * @return {Roo.Element} this
7690          */
7691          setHeight : function(height, animate){
7692             height = this.adjustHeight(height);
7693             if(!animate || !A){
7694                 this.dom.style.height = this.addUnits(height);
7695             }else{
7696                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7697             }
7698             return this;
7699         },
7700
7701         /**
7702          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7703          * @param {Number} width The new width
7704          * @param {Number} height The new height
7705          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7706          * @return {Roo.Element} this
7707          */
7708          setSize : function(width, height, animate){
7709             if(typeof width == "object"){ // in case of object from getSize()
7710                 height = width.height; width = width.width;
7711             }
7712             width = this.adjustWidth(width); height = this.adjustHeight(height);
7713             if(!animate || !A){
7714                 this.dom.style.width = this.addUnits(width);
7715                 this.dom.style.height = this.addUnits(height);
7716             }else{
7717                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7718             }
7719             return this;
7720         },
7721
7722         /**
7723          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7724          * @param {Number} x X value for new position (coordinates are page-based)
7725          * @param {Number} y Y value for new position (coordinates are page-based)
7726          * @param {Number} width The new width
7727          * @param {Number} height The new height
7728          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7729          * @return {Roo.Element} this
7730          */
7731         setBounds : function(x, y, width, height, animate){
7732             if(!animate || !A){
7733                 this.setSize(width, height);
7734                 this.setLocation(x, y);
7735             }else{
7736                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7737                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7738                               this.preanim(arguments, 4), 'motion');
7739             }
7740             return this;
7741         },
7742
7743         /**
7744          * 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.
7745          * @param {Roo.lib.Region} region The region to fill
7746          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7747          * @return {Roo.Element} this
7748          */
7749         setRegion : function(region, animate){
7750             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7751             return this;
7752         },
7753
7754         /**
7755          * Appends an event handler
7756          *
7757          * @param {String}   eventName     The type of event to append
7758          * @param {Function} fn        The method the event invokes
7759          * @param {Object} scope       (optional) The scope (this object) of the fn
7760          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7761          */
7762         addListener : function(eventName, fn, scope, options){
7763             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7764         },
7765
7766         /**
7767          * Removes an event handler from this element
7768          * @param {String} eventName the type of event to remove
7769          * @param {Function} fn the method the event invokes
7770          * @return {Roo.Element} this
7771          */
7772         removeListener : function(eventName, fn){
7773             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7774             return this;
7775         },
7776
7777         /**
7778          * Removes all previous added listeners from this element
7779          * @return {Roo.Element} this
7780          */
7781         removeAllListeners : function(){
7782             E.purgeElement(this.dom);
7783             return this;
7784         },
7785
7786         relayEvent : function(eventName, observable){
7787             this.on(eventName, function(e){
7788                 observable.fireEvent(eventName, e);
7789             });
7790         },
7791
7792         /**
7793          * Set the opacity of the element
7794          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7795          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7796          * @return {Roo.Element} this
7797          */
7798          setOpacity : function(opacity, animate){
7799             if(!animate || !A){
7800                 var s = this.dom.style;
7801                 if(Roo.isIE){
7802                     s.zoom = 1;
7803                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7804                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7805                 }else{
7806                     s.opacity = opacity;
7807                 }
7808             }else{
7809                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7810             }
7811             return this;
7812         },
7813
7814         /**
7815          * Gets the left X coordinate
7816          * @param {Boolean} local True to get the local css position instead of page coordinate
7817          * @return {Number}
7818          */
7819         getLeft : function(local){
7820             if(!local){
7821                 return this.getX();
7822             }else{
7823                 return parseInt(this.getStyle("left"), 10) || 0;
7824             }
7825         },
7826
7827         /**
7828          * Gets the right X coordinate of the element (element X position + element width)
7829          * @param {Boolean} local True to get the local css position instead of page coordinate
7830          * @return {Number}
7831          */
7832         getRight : function(local){
7833             if(!local){
7834                 return this.getX() + this.getWidth();
7835             }else{
7836                 return (this.getLeft(true) + this.getWidth()) || 0;
7837             }
7838         },
7839
7840         /**
7841          * Gets the top Y coordinate
7842          * @param {Boolean} local True to get the local css position instead of page coordinate
7843          * @return {Number}
7844          */
7845         getTop : function(local) {
7846             if(!local){
7847                 return this.getY();
7848             }else{
7849                 return parseInt(this.getStyle("top"), 10) || 0;
7850             }
7851         },
7852
7853         /**
7854          * Gets the bottom Y coordinate of the element (element Y position + element height)
7855          * @param {Boolean} local True to get the local css position instead of page coordinate
7856          * @return {Number}
7857          */
7858         getBottom : function(local){
7859             if(!local){
7860                 return this.getY() + this.getHeight();
7861             }else{
7862                 return (this.getTop(true) + this.getHeight()) || 0;
7863             }
7864         },
7865
7866         /**
7867         * Initializes positioning on this element. If a desired position is not passed, it will make the
7868         * the element positioned relative IF it is not already positioned.
7869         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7870         * @param {Number} zIndex (optional) The zIndex to apply
7871         * @param {Number} x (optional) Set the page X position
7872         * @param {Number} y (optional) Set the page Y position
7873         */
7874         position : function(pos, zIndex, x, y){
7875             if(!pos){
7876                if(this.getStyle('position') == 'static'){
7877                    this.setStyle('position', 'relative');
7878                }
7879             }else{
7880                 this.setStyle("position", pos);
7881             }
7882             if(zIndex){
7883                 this.setStyle("z-index", zIndex);
7884             }
7885             if(x !== undefined && y !== undefined){
7886                 this.setXY([x, y]);
7887             }else if(x !== undefined){
7888                 this.setX(x);
7889             }else if(y !== undefined){
7890                 this.setY(y);
7891             }
7892         },
7893
7894         /**
7895         * Clear positioning back to the default when the document was loaded
7896         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7897         * @return {Roo.Element} this
7898          */
7899         clearPositioning : function(value){
7900             value = value ||'';
7901             this.setStyle({
7902                 "left": value,
7903                 "right": value,
7904                 "top": value,
7905                 "bottom": value,
7906                 "z-index": "",
7907                 "position" : "static"
7908             });
7909             return this;
7910         },
7911
7912         /**
7913         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7914         * snapshot before performing an update and then restoring the element.
7915         * @return {Object}
7916         */
7917         getPositioning : function(){
7918             var l = this.getStyle("left");
7919             var t = this.getStyle("top");
7920             return {
7921                 "position" : this.getStyle("position"),
7922                 "left" : l,
7923                 "right" : l ? "" : this.getStyle("right"),
7924                 "top" : t,
7925                 "bottom" : t ? "" : this.getStyle("bottom"),
7926                 "z-index" : this.getStyle("z-index")
7927             };
7928         },
7929
7930         /**
7931          * Gets the width of the border(s) for the specified side(s)
7932          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7933          * passing lr would get the border (l)eft width + the border (r)ight width.
7934          * @return {Number} The width of the sides passed added together
7935          */
7936         getBorderWidth : function(side){
7937             return this.addStyles(side, El.borders);
7938         },
7939
7940         /**
7941          * Gets the width of the padding(s) for the specified side(s)
7942          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7943          * passing lr would get the padding (l)eft + the padding (r)ight.
7944          * @return {Number} The padding of the sides passed added together
7945          */
7946         getPadding : function(side){
7947             return this.addStyles(side, El.paddings);
7948         },
7949
7950         /**
7951         * Set positioning with an object returned by getPositioning().
7952         * @param {Object} posCfg
7953         * @return {Roo.Element} this
7954          */
7955         setPositioning : function(pc){
7956             this.applyStyles(pc);
7957             if(pc.right == "auto"){
7958                 this.dom.style.right = "";
7959             }
7960             if(pc.bottom == "auto"){
7961                 this.dom.style.bottom = "";
7962             }
7963             return this;
7964         },
7965
7966         // private
7967         fixDisplay : function(){
7968             if(this.getStyle("display") == "none"){
7969                 this.setStyle("visibility", "hidden");
7970                 this.setStyle("display", this.originalDisplay); // first try reverting to default
7971                 if(this.getStyle("display") == "none"){ // if that fails, default to block
7972                     this.setStyle("display", "block");
7973                 }
7974             }
7975         },
7976
7977         /**
7978          * Quick set left and top adding default units
7979          * @param {String} left The left CSS property value
7980          * @param {String} top The top CSS property value
7981          * @return {Roo.Element} this
7982          */
7983          setLeftTop : function(left, top){
7984             this.dom.style.left = this.addUnits(left);
7985             this.dom.style.top = this.addUnits(top);
7986             return this;
7987         },
7988
7989         /**
7990          * Move this element relative to its current position.
7991          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7992          * @param {Number} distance How far to move the element in pixels
7993          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7994          * @return {Roo.Element} this
7995          */
7996          move : function(direction, distance, animate){
7997             var xy = this.getXY();
7998             direction = direction.toLowerCase();
7999             switch(direction){
8000                 case "l":
8001                 case "left":
8002                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8003                     break;
8004                case "r":
8005                case "right":
8006                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8007                     break;
8008                case "t":
8009                case "top":
8010                case "up":
8011                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8012                     break;
8013                case "b":
8014                case "bottom":
8015                case "down":
8016                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8017                     break;
8018             }
8019             return this;
8020         },
8021
8022         /**
8023          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8024          * @return {Roo.Element} this
8025          */
8026         clip : function(){
8027             if(!this.isClipped){
8028                this.isClipped = true;
8029                this.originalClip = {
8030                    "o": this.getStyle("overflow"),
8031                    "x": this.getStyle("overflow-x"),
8032                    "y": this.getStyle("overflow-y")
8033                };
8034                this.setStyle("overflow", "hidden");
8035                this.setStyle("overflow-x", "hidden");
8036                this.setStyle("overflow-y", "hidden");
8037             }
8038             return this;
8039         },
8040
8041         /**
8042          *  Return clipping (overflow) to original clipping before clip() was called
8043          * @return {Roo.Element} this
8044          */
8045         unclip : function(){
8046             if(this.isClipped){
8047                 this.isClipped = false;
8048                 var o = this.originalClip;
8049                 if(o.o){this.setStyle("overflow", o.o);}
8050                 if(o.x){this.setStyle("overflow-x", o.x);}
8051                 if(o.y){this.setStyle("overflow-y", o.y);}
8052             }
8053             return this;
8054         },
8055
8056
8057         /**
8058          * Gets the x,y coordinates specified by the anchor position on the element.
8059          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8060          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8061          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8062          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8063          * @return {Array} [x, y] An array containing the element's x and y coordinates
8064          */
8065         getAnchorXY : function(anchor, local, s){
8066             //Passing a different size is useful for pre-calculating anchors,
8067             //especially for anchored animations that change the el size.
8068
8069             var w, h, vp = false;
8070             if(!s){
8071                 var d = this.dom;
8072                 if(d == document.body || d == document){
8073                     vp = true;
8074                     w = D.getViewWidth(); h = D.getViewHeight();
8075                 }else{
8076                     w = this.getWidth(); h = this.getHeight();
8077                 }
8078             }else{
8079                 w = s.width;  h = s.height;
8080             }
8081             var x = 0, y = 0, r = Math.round;
8082             switch((anchor || "tl").toLowerCase()){
8083                 case "c":
8084                     x = r(w*.5);
8085                     y = r(h*.5);
8086                 break;
8087                 case "t":
8088                     x = r(w*.5);
8089                     y = 0;
8090                 break;
8091                 case "l":
8092                     x = 0;
8093                     y = r(h*.5);
8094                 break;
8095                 case "r":
8096                     x = w;
8097                     y = r(h*.5);
8098                 break;
8099                 case "b":
8100                     x = r(w*.5);
8101                     y = h;
8102                 break;
8103                 case "tl":
8104                     x = 0;
8105                     y = 0;
8106                 break;
8107                 case "bl":
8108                     x = 0;
8109                     y = h;
8110                 break;
8111                 case "br":
8112                     x = w;
8113                     y = h;
8114                 break;
8115                 case "tr":
8116                     x = w;
8117                     y = 0;
8118                 break;
8119             }
8120             if(local === true){
8121                 return [x, y];
8122             }
8123             if(vp){
8124                 var sc = this.getScroll();
8125                 return [x + sc.left, y + sc.top];
8126             }
8127             //Add the element's offset xy
8128             var o = this.getXY();
8129             return [x+o[0], y+o[1]];
8130         },
8131
8132         /**
8133          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8134          * supported position values.
8135          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8136          * @param {String} position The position to align to.
8137          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8138          * @return {Array} [x, y]
8139          */
8140         getAlignToXY : function(el, p, o){
8141             el = Roo.get(el);
8142             var d = this.dom;
8143             if(!el.dom){
8144                 throw "Element.alignTo with an element that doesn't exist";
8145             }
8146             var c = false; //constrain to viewport
8147             var p1 = "", p2 = "";
8148             o = o || [0,0];
8149
8150             if(!p){
8151                 p = "tl-bl";
8152             }else if(p == "?"){
8153                 p = "tl-bl?";
8154             }else if(p.indexOf("-") == -1){
8155                 p = "tl-" + p;
8156             }
8157             p = p.toLowerCase();
8158             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8159             if(!m){
8160                throw "Element.alignTo with an invalid alignment " + p;
8161             }
8162             p1 = m[1]; p2 = m[2]; c = !!m[3];
8163
8164             //Subtract the aligned el's internal xy from the target's offset xy
8165             //plus custom offset to get the aligned el's new offset xy
8166             var a1 = this.getAnchorXY(p1, true);
8167             var a2 = el.getAnchorXY(p2, false);
8168             var x = a2[0] - a1[0] + o[0];
8169             var y = a2[1] - a1[1] + o[1];
8170             if(c){
8171                 //constrain the aligned el to viewport if necessary
8172                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8173                 // 5px of margin for ie
8174                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8175
8176                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8177                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8178                 //otherwise swap the aligned el to the opposite border of the target.
8179                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8180                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8181                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8182                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8183
8184                var doc = document;
8185                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8186                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8187
8188                if((x+w) > dw + scrollX){
8189                     x = swapX ? r.left-w : dw+scrollX-w;
8190                 }
8191                if(x < scrollX){
8192                    x = swapX ? r.right : scrollX;
8193                }
8194                if((y+h) > dh + scrollY){
8195                     y = swapY ? r.top-h : dh+scrollY-h;
8196                 }
8197                if (y < scrollY){
8198                    y = swapY ? r.bottom : scrollY;
8199                }
8200             }
8201             return [x,y];
8202         },
8203
8204         // private
8205         getConstrainToXY : function(){
8206             var os = {top:0, left:0, bottom:0, right: 0};
8207
8208             return function(el, local, offsets, proposedXY){
8209                 el = Roo.get(el);
8210                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8211
8212                 var vw, vh, vx = 0, vy = 0;
8213                 if(el.dom == document.body || el.dom == document){
8214                     vw = Roo.lib.Dom.getViewWidth();
8215                     vh = Roo.lib.Dom.getViewHeight();
8216                 }else{
8217                     vw = el.dom.clientWidth;
8218                     vh = el.dom.clientHeight;
8219                     if(!local){
8220                         var vxy = el.getXY();
8221                         vx = vxy[0];
8222                         vy = vxy[1];
8223                     }
8224                 }
8225
8226                 var s = el.getScroll();
8227
8228                 vx += offsets.left + s.left;
8229                 vy += offsets.top + s.top;
8230
8231                 vw -= offsets.right;
8232                 vh -= offsets.bottom;
8233
8234                 var vr = vx+vw;
8235                 var vb = vy+vh;
8236
8237                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8238                 var x = xy[0], y = xy[1];
8239                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8240
8241                 // only move it if it needs it
8242                 var moved = false;
8243
8244                 // first validate right/bottom
8245                 if((x + w) > vr){
8246                     x = vr - w;
8247                     moved = true;
8248                 }
8249                 if((y + h) > vb){
8250                     y = vb - h;
8251                     moved = true;
8252                 }
8253                 // then make sure top/left isn't negative
8254                 if(x < vx){
8255                     x = vx;
8256                     moved = true;
8257                 }
8258                 if(y < vy){
8259                     y = vy;
8260                     moved = true;
8261                 }
8262                 return moved ? [x, y] : false;
8263             };
8264         }(),
8265
8266         // private
8267         adjustForConstraints : function(xy, parent, offsets){
8268             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8269         },
8270
8271         /**
8272          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8273          * document it aligns it to the viewport.
8274          * The position parameter is optional, and can be specified in any one of the following formats:
8275          * <ul>
8276          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8277          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8278          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8279          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8280          *   <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
8281          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8282          * </ul>
8283          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8284          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8285          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8286          * that specified in order to enforce the viewport constraints.
8287          * Following are all of the supported anchor positions:
8288     <pre>
8289     Value  Description
8290     -----  -----------------------------
8291     tl     The top left corner (default)
8292     t      The center of the top edge
8293     tr     The top right corner
8294     l      The center of the left edge
8295     c      In the center of the element
8296     r      The center of the right edge
8297     bl     The bottom left corner
8298     b      The center of the bottom edge
8299     br     The bottom right corner
8300     </pre>
8301     Example Usage:
8302     <pre><code>
8303     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8304     el.alignTo("other-el");
8305
8306     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8307     el.alignTo("other-el", "tr?");
8308
8309     // align the bottom right corner of el with the center left edge of other-el
8310     el.alignTo("other-el", "br-l?");
8311
8312     // align the center of el with the bottom left corner of other-el and
8313     // adjust the x position by -6 pixels (and the y position by 0)
8314     el.alignTo("other-el", "c-bl", [-6, 0]);
8315     </code></pre>
8316          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8317          * @param {String} position The position to align to.
8318          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8319          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8320          * @return {Roo.Element} this
8321          */
8322         alignTo : function(element, position, offsets, animate){
8323             var xy = this.getAlignToXY(element, position, offsets);
8324             this.setXY(xy, this.preanim(arguments, 3));
8325             return this;
8326         },
8327
8328         /**
8329          * Anchors an element to another element and realigns it when the window is resized.
8330          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8331          * @param {String} position The position to align to.
8332          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8333          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8334          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8335          * is a number, it is used as the buffer delay (defaults to 50ms).
8336          * @param {Function} callback The function to call after the animation finishes
8337          * @return {Roo.Element} this
8338          */
8339         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8340             var action = function(){
8341                 this.alignTo(el, alignment, offsets, animate);
8342                 Roo.callback(callback, this);
8343             };
8344             Roo.EventManager.onWindowResize(action, this);
8345             var tm = typeof monitorScroll;
8346             if(tm != 'undefined'){
8347                 Roo.EventManager.on(window, 'scroll', action, this,
8348                     {buffer: tm == 'number' ? monitorScroll : 50});
8349             }
8350             action.call(this); // align immediately
8351             return this;
8352         },
8353         /**
8354          * Clears any opacity settings from this element. Required in some cases for IE.
8355          * @return {Roo.Element} this
8356          */
8357         clearOpacity : function(){
8358             if (window.ActiveXObject) {
8359                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8360                     this.dom.style.filter = "";
8361                 }
8362             } else {
8363                 this.dom.style.opacity = "";
8364                 this.dom.style["-moz-opacity"] = "";
8365                 this.dom.style["-khtml-opacity"] = "";
8366             }
8367             return this;
8368         },
8369
8370         /**
8371          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8372          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8373          * @return {Roo.Element} this
8374          */
8375         hide : function(animate){
8376             this.setVisible(false, this.preanim(arguments, 0));
8377             return this;
8378         },
8379
8380         /**
8381         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8382         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8383          * @return {Roo.Element} this
8384          */
8385         show : function(animate){
8386             this.setVisible(true, this.preanim(arguments, 0));
8387             return this;
8388         },
8389
8390         /**
8391          * @private Test if size has a unit, otherwise appends the default
8392          */
8393         addUnits : function(size){
8394             return Roo.Element.addUnits(size, this.defaultUnit);
8395         },
8396
8397         /**
8398          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8399          * @return {Roo.Element} this
8400          */
8401         beginMeasure : function(){
8402             var el = this.dom;
8403             if(el.offsetWidth || el.offsetHeight){
8404                 return this; // offsets work already
8405             }
8406             var changed = [];
8407             var p = this.dom, b = document.body; // start with this element
8408             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8409                 var pe = Roo.get(p);
8410                 if(pe.getStyle('display') == 'none'){
8411                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8412                     p.style.visibility = "hidden";
8413                     p.style.display = "block";
8414                 }
8415                 p = p.parentNode;
8416             }
8417             this._measureChanged = changed;
8418             return this;
8419
8420         },
8421
8422         /**
8423          * Restores displays to before beginMeasure was called
8424          * @return {Roo.Element} this
8425          */
8426         endMeasure : function(){
8427             var changed = this._measureChanged;
8428             if(changed){
8429                 for(var i = 0, len = changed.length; i < len; i++) {
8430                     var r = changed[i];
8431                     r.el.style.visibility = r.visibility;
8432                     r.el.style.display = "none";
8433                 }
8434                 this._measureChanged = null;
8435             }
8436             return this;
8437         },
8438
8439         /**
8440         * Update the innerHTML of this element, optionally searching for and processing scripts
8441         * @param {String} html The new HTML
8442         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8443         * @param {Function} callback For async script loading you can be noticed when the update completes
8444         * @return {Roo.Element} this
8445          */
8446         update : function(html, loadScripts, callback){
8447             if(typeof html == "undefined"){
8448                 html = "";
8449             }
8450             if(loadScripts !== true){
8451                 this.dom.innerHTML = html;
8452                 if(typeof callback == "function"){
8453                     callback();
8454                 }
8455                 return this;
8456             }
8457             var id = Roo.id();
8458             var dom = this.dom;
8459
8460             html += '<span id="' + id + '"></span>';
8461
8462             E.onAvailable(id, function(){
8463                 var hd = document.getElementsByTagName("head")[0];
8464                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8465                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8466                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8467
8468                 var match;
8469                 while(match = re.exec(html)){
8470                     var attrs = match[1];
8471                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8472                     if(srcMatch && srcMatch[2]){
8473                        var s = document.createElement("script");
8474                        s.src = srcMatch[2];
8475                        var typeMatch = attrs.match(typeRe);
8476                        if(typeMatch && typeMatch[2]){
8477                            s.type = typeMatch[2];
8478                        }
8479                        hd.appendChild(s);
8480                     }else if(match[2] && match[2].length > 0){
8481                         if(window.execScript) {
8482                            window.execScript(match[2]);
8483                         } else {
8484                             /**
8485                              * eval:var:id
8486                              * eval:var:dom
8487                              * eval:var:html
8488                              * 
8489                              */
8490                            window.eval(match[2]);
8491                         }
8492                     }
8493                 }
8494                 var el = document.getElementById(id);
8495                 if(el){el.parentNode.removeChild(el);}
8496                 if(typeof callback == "function"){
8497                     callback();
8498                 }
8499             });
8500             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8501             return this;
8502         },
8503
8504         /**
8505          * Direct access to the UpdateManager update() method (takes the same parameters).
8506          * @param {String/Function} url The url for this request or a function to call to get the url
8507          * @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}
8508          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8509          * @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.
8510          * @return {Roo.Element} this
8511          */
8512         load : function(){
8513             var um = this.getUpdateManager();
8514             um.update.apply(um, arguments);
8515             return this;
8516         },
8517
8518         /**
8519         * Gets this element's UpdateManager
8520         * @return {Roo.UpdateManager} The UpdateManager
8521         */
8522         getUpdateManager : function(){
8523             if(!this.updateManager){
8524                 this.updateManager = new Roo.UpdateManager(this);
8525             }
8526             return this.updateManager;
8527         },
8528
8529         /**
8530          * Disables text selection for this element (normalized across browsers)
8531          * @return {Roo.Element} this
8532          */
8533         unselectable : function(){
8534             this.dom.unselectable = "on";
8535             this.swallowEvent("selectstart", true);
8536             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8537             this.addClass("x-unselectable");
8538             return this;
8539         },
8540
8541         /**
8542         * Calculates the x, y to center this element on the screen
8543         * @return {Array} The x, y values [x, y]
8544         */
8545         getCenterXY : function(){
8546             return this.getAlignToXY(document, 'c-c');
8547         },
8548
8549         /**
8550         * Centers the Element in either the viewport, or another Element.
8551         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8552         */
8553         center : function(centerIn){
8554             this.alignTo(centerIn || document, 'c-c');
8555             return this;
8556         },
8557
8558         /**
8559          * Tests various css rules/browsers to determine if this element uses a border box
8560          * @return {Boolean}
8561          */
8562         isBorderBox : function(){
8563             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8564         },
8565
8566         /**
8567          * Return a box {x, y, width, height} that can be used to set another elements
8568          * size/location to match this element.
8569          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8570          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8571          * @return {Object} box An object in the format {x, y, width, height}
8572          */
8573         getBox : function(contentBox, local){
8574             var xy;
8575             if(!local){
8576                 xy = this.getXY();
8577             }else{
8578                 var left = parseInt(this.getStyle("left"), 10) || 0;
8579                 var top = parseInt(this.getStyle("top"), 10) || 0;
8580                 xy = [left, top];
8581             }
8582             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8583             if(!contentBox){
8584                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8585             }else{
8586                 var l = this.getBorderWidth("l")+this.getPadding("l");
8587                 var r = this.getBorderWidth("r")+this.getPadding("r");
8588                 var t = this.getBorderWidth("t")+this.getPadding("t");
8589                 var b = this.getBorderWidth("b")+this.getPadding("b");
8590                 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)};
8591             }
8592             bx.right = bx.x + bx.width;
8593             bx.bottom = bx.y + bx.height;
8594             return bx;
8595         },
8596
8597         /**
8598          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8599          for more information about the sides.
8600          * @param {String} sides
8601          * @return {Number}
8602          */
8603         getFrameWidth : function(sides, onlyContentBox){
8604             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8605         },
8606
8607         /**
8608          * 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.
8609          * @param {Object} box The box to fill {x, y, width, height}
8610          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8611          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8612          * @return {Roo.Element} this
8613          */
8614         setBox : function(box, adjust, animate){
8615             var w = box.width, h = box.height;
8616             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8617                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8618                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8619             }
8620             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8621             return this;
8622         },
8623
8624         /**
8625          * Forces the browser to repaint this element
8626          * @return {Roo.Element} this
8627          */
8628          repaint : function(){
8629             var dom = this.dom;
8630             this.addClass("x-repaint");
8631             setTimeout(function(){
8632                 Roo.get(dom).removeClass("x-repaint");
8633             }, 1);
8634             return this;
8635         },
8636
8637         /**
8638          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8639          * then it returns the calculated width of the sides (see getPadding)
8640          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8641          * @return {Object/Number}
8642          */
8643         getMargins : function(side){
8644             if(!side){
8645                 return {
8646                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8647                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8648                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8649                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8650                 };
8651             }else{
8652                 return this.addStyles(side, El.margins);
8653              }
8654         },
8655
8656         // private
8657         addStyles : function(sides, styles){
8658             var val = 0, v, w;
8659             for(var i = 0, len = sides.length; i < len; i++){
8660                 v = this.getStyle(styles[sides.charAt(i)]);
8661                 if(v){
8662                      w = parseInt(v, 10);
8663                      if(w){ val += w; }
8664                 }
8665             }
8666             return val;
8667         },
8668
8669         /**
8670          * Creates a proxy element of this element
8671          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8672          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8673          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8674          * @return {Roo.Element} The new proxy element
8675          */
8676         createProxy : function(config, renderTo, matchBox){
8677             if(renderTo){
8678                 renderTo = Roo.getDom(renderTo);
8679             }else{
8680                 renderTo = document.body;
8681             }
8682             config = typeof config == "object" ?
8683                 config : {tag : "div", cls: config};
8684             var proxy = Roo.DomHelper.append(renderTo, config, true);
8685             if(matchBox){
8686                proxy.setBox(this.getBox());
8687             }
8688             return proxy;
8689         },
8690
8691         /**
8692          * Puts a mask over this element to disable user interaction. Requires core.css.
8693          * This method can only be applied to elements which accept child nodes.
8694          * @param {String} msg (optional) A message to display in the mask
8695          * @param {String} msgCls (optional) A css class to apply to the msg element
8696          * @return {Element} The mask  element
8697          */
8698         mask : function(msg, msgCls){
8699             if(this.getStyle("position") == "static"){
8700                 this.setStyle("position", "relative");
8701             }
8702             if(!this._mask){
8703                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8704             }
8705             this.addClass("x-masked");
8706             this._mask.setDisplayed(true);
8707             if(typeof msg == 'string'){
8708                 if(!this._maskMsg){
8709                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8710                 }
8711                 var mm = this._maskMsg;
8712                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8713                 mm.dom.firstChild.innerHTML = msg;
8714                 mm.setDisplayed(true);
8715                 mm.center(this);
8716             }
8717             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8718                 this._mask.setHeight(this.getHeight());
8719             }
8720             return this._mask;
8721         },
8722
8723         /**
8724          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8725          * it is cached for reuse.
8726          */
8727         unmask : function(removeEl){
8728             if(this._mask){
8729                 if(removeEl === true){
8730                     this._mask.remove();
8731                     delete this._mask;
8732                     if(this._maskMsg){
8733                         this._maskMsg.remove();
8734                         delete this._maskMsg;
8735                     }
8736                 }else{
8737                     this._mask.setDisplayed(false);
8738                     if(this._maskMsg){
8739                         this._maskMsg.setDisplayed(false);
8740                     }
8741                 }
8742             }
8743             this.removeClass("x-masked");
8744         },
8745
8746         /**
8747          * Returns true if this element is masked
8748          * @return {Boolean}
8749          */
8750         isMasked : function(){
8751             return this._mask && this._mask.isVisible();
8752         },
8753
8754         /**
8755          * Creates an iframe shim for this element to keep selects and other windowed objects from
8756          * showing through.
8757          * @return {Roo.Element} The new shim element
8758          */
8759         createShim : function(){
8760             var el = document.createElement('iframe');
8761             el.frameBorder = 'no';
8762             el.className = 'roo-shim';
8763             if(Roo.isIE && Roo.isSecure){
8764                 el.src = Roo.SSL_SECURE_URL;
8765             }
8766             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8767             shim.autoBoxAdjust = false;
8768             return shim;
8769         },
8770
8771         /**
8772          * Removes this element from the DOM and deletes it from the cache
8773          */
8774         remove : function(){
8775             if(this.dom.parentNode){
8776                 this.dom.parentNode.removeChild(this.dom);
8777             }
8778             delete El.cache[this.dom.id];
8779         },
8780
8781         /**
8782          * Sets up event handlers to add and remove a css class when the mouse is over this element
8783          * @param {String} className
8784          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8785          * mouseout events for children elements
8786          * @return {Roo.Element} this
8787          */
8788         addClassOnOver : function(className, preventFlicker){
8789             this.on("mouseover", function(){
8790                 Roo.fly(this, '_internal').addClass(className);
8791             }, this.dom);
8792             var removeFn = function(e){
8793                 if(preventFlicker !== true || !e.within(this, true)){
8794                     Roo.fly(this, '_internal').removeClass(className);
8795                 }
8796             };
8797             this.on("mouseout", removeFn, this.dom);
8798             return this;
8799         },
8800
8801         /**
8802          * Sets up event handlers to add and remove a css class when this element has the focus
8803          * @param {String} className
8804          * @return {Roo.Element} this
8805          */
8806         addClassOnFocus : function(className){
8807             this.on("focus", function(){
8808                 Roo.fly(this, '_internal').addClass(className);
8809             }, this.dom);
8810             this.on("blur", function(){
8811                 Roo.fly(this, '_internal').removeClass(className);
8812             }, this.dom);
8813             return this;
8814         },
8815         /**
8816          * 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)
8817          * @param {String} className
8818          * @return {Roo.Element} this
8819          */
8820         addClassOnClick : function(className){
8821             var dom = this.dom;
8822             this.on("mousedown", function(){
8823                 Roo.fly(dom, '_internal').addClass(className);
8824                 var d = Roo.get(document);
8825                 var fn = function(){
8826                     Roo.fly(dom, '_internal').removeClass(className);
8827                     d.removeListener("mouseup", fn);
8828                 };
8829                 d.on("mouseup", fn);
8830             });
8831             return this;
8832         },
8833
8834         /**
8835          * Stops the specified event from bubbling and optionally prevents the default action
8836          * @param {String} eventName
8837          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8838          * @return {Roo.Element} this
8839          */
8840         swallowEvent : function(eventName, preventDefault){
8841             var fn = function(e){
8842                 e.stopPropagation();
8843                 if(preventDefault){
8844                     e.preventDefault();
8845                 }
8846             };
8847             if(eventName instanceof Array){
8848                 for(var i = 0, len = eventName.length; i < len; i++){
8849                      this.on(eventName[i], fn);
8850                 }
8851                 return this;
8852             }
8853             this.on(eventName, fn);
8854             return this;
8855         },
8856
8857         /**
8858          * @private
8859          */
8860       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8861
8862         /**
8863          * Sizes this element to its parent element's dimensions performing
8864          * neccessary box adjustments.
8865          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8866          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8867          * @return {Roo.Element} this
8868          */
8869         fitToParent : function(monitorResize, targetParent) {
8870           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8871           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8872           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8873             return;
8874           }
8875           var p = Roo.get(targetParent || this.dom.parentNode);
8876           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8877           if (monitorResize === true) {
8878             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8879             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8880           }
8881           return this;
8882         },
8883
8884         /**
8885          * Gets the next sibling, skipping text nodes
8886          * @return {HTMLElement} The next sibling or null
8887          */
8888         getNextSibling : function(){
8889             var n = this.dom.nextSibling;
8890             while(n && n.nodeType != 1){
8891                 n = n.nextSibling;
8892             }
8893             return n;
8894         },
8895
8896         /**
8897          * Gets the previous sibling, skipping text nodes
8898          * @return {HTMLElement} The previous sibling or null
8899          */
8900         getPrevSibling : function(){
8901             var n = this.dom.previousSibling;
8902             while(n && n.nodeType != 1){
8903                 n = n.previousSibling;
8904             }
8905             return n;
8906         },
8907
8908
8909         /**
8910          * Appends the passed element(s) to this element
8911          * @param {String/HTMLElement/Array/Element/CompositeElement} el
8912          * @return {Roo.Element} this
8913          */
8914         appendChild: function(el){
8915             el = Roo.get(el);
8916             el.appendTo(this);
8917             return this;
8918         },
8919
8920         /**
8921          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8922          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
8923          * automatically generated with the specified attributes.
8924          * @param {HTMLElement} insertBefore (optional) a child element of this element
8925          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8926          * @return {Roo.Element} The new child element
8927          */
8928         createChild: function(config, insertBefore, returnDom){
8929             config = config || {tag:'div'};
8930             if(insertBefore){
8931                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8932             }
8933             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
8934         },
8935
8936         /**
8937          * Appends this element to the passed element
8938          * @param {String/HTMLElement/Element} el The new parent element
8939          * @return {Roo.Element} this
8940          */
8941         appendTo: function(el){
8942             el = Roo.getDom(el);
8943             el.appendChild(this.dom);
8944             return this;
8945         },
8946
8947         /**
8948          * Inserts this element before the passed element in the DOM
8949          * @param {String/HTMLElement/Element} el The element to insert before
8950          * @return {Roo.Element} this
8951          */
8952         insertBefore: function(el){
8953             el = Roo.getDom(el);
8954             el.parentNode.insertBefore(this.dom, el);
8955             return this;
8956         },
8957
8958         /**
8959          * Inserts this element after the passed element in the DOM
8960          * @param {String/HTMLElement/Element} el The element to insert after
8961          * @return {Roo.Element} this
8962          */
8963         insertAfter: function(el){
8964             el = Roo.getDom(el);
8965             el.parentNode.insertBefore(this.dom, el.nextSibling);
8966             return this;
8967         },
8968
8969         /**
8970          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8971          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8972          * @return {Roo.Element} The new child
8973          */
8974         insertFirst: function(el, returnDom){
8975             el = el || {};
8976             if(typeof el == 'object' && !el.nodeType){ // dh config
8977                 return this.createChild(el, this.dom.firstChild, returnDom);
8978             }else{
8979                 el = Roo.getDom(el);
8980                 this.dom.insertBefore(el, this.dom.firstChild);
8981                 return !returnDom ? Roo.get(el) : el;
8982             }
8983         },
8984
8985         /**
8986          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8987          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8988          * @param {String} where (optional) 'before' or 'after' defaults to before
8989          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8990          * @return {Roo.Element} the inserted Element
8991          */
8992         insertSibling: function(el, where, returnDom){
8993             where = where ? where.toLowerCase() : 'before';
8994             el = el || {};
8995             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8996
8997             if(typeof el == 'object' && !el.nodeType){ // dh config
8998                 if(where == 'after' && !this.dom.nextSibling){
8999                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9000                 }else{
9001                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9002                 }
9003
9004             }else{
9005                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9006                             where == 'before' ? this.dom : this.dom.nextSibling);
9007                 if(!returnDom){
9008                     rt = Roo.get(rt);
9009                 }
9010             }
9011             return rt;
9012         },
9013
9014         /**
9015          * Creates and wraps this element with another element
9016          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9017          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9018          * @return {HTMLElement/Element} The newly created wrapper element
9019          */
9020         wrap: function(config, returnDom){
9021             if(!config){
9022                 config = {tag: "div"};
9023             }
9024             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9025             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9026             return newEl;
9027         },
9028
9029         /**
9030          * Replaces the passed element with this element
9031          * @param {String/HTMLElement/Element} el The element to replace
9032          * @return {Roo.Element} this
9033          */
9034         replace: function(el){
9035             el = Roo.get(el);
9036             this.insertBefore(el);
9037             el.remove();
9038             return this;
9039         },
9040
9041         /**
9042          * Inserts an html fragment into this element
9043          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9044          * @param {String} html The HTML fragment
9045          * @param {Boolean} returnEl True to return an Roo.Element
9046          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9047          */
9048         insertHtml : function(where, html, returnEl){
9049             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9050             return returnEl ? Roo.get(el) : el;
9051         },
9052
9053         /**
9054          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9055          * @param {Object} o The object with the attributes
9056          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9057          * @return {Roo.Element} this
9058          */
9059         set : function(o, useSet){
9060             var el = this.dom;
9061             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9062             for(var attr in o){
9063                 if(attr == "style" || typeof o[attr] == "function") continue;
9064                 if(attr=="cls"){
9065                     el.className = o["cls"];
9066                 }else{
9067                     if(useSet) el.setAttribute(attr, o[attr]);
9068                     else el[attr] = o[attr];
9069                 }
9070             }
9071             if(o.style){
9072                 Roo.DomHelper.applyStyles(el, o.style);
9073             }
9074             return this;
9075         },
9076
9077         /**
9078          * Convenience method for constructing a KeyMap
9079          * @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:
9080          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9081          * @param {Function} fn The function to call
9082          * @param {Object} scope (optional) The scope of the function
9083          * @return {Roo.KeyMap} The KeyMap created
9084          */
9085         addKeyListener : function(key, fn, scope){
9086             var config;
9087             if(typeof key != "object" || key instanceof Array){
9088                 config = {
9089                     key: key,
9090                     fn: fn,
9091                     scope: scope
9092                 };
9093             }else{
9094                 config = {
9095                     key : key.key,
9096                     shift : key.shift,
9097                     ctrl : key.ctrl,
9098                     alt : key.alt,
9099                     fn: fn,
9100                     scope: scope
9101                 };
9102             }
9103             return new Roo.KeyMap(this, config);
9104         },
9105
9106         /**
9107          * Creates a KeyMap for this element
9108          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9109          * @return {Roo.KeyMap} The KeyMap created
9110          */
9111         addKeyMap : function(config){
9112             return new Roo.KeyMap(this, config);
9113         },
9114
9115         /**
9116          * Returns true if this element is scrollable.
9117          * @return {Boolean}
9118          */
9119          isScrollable : function(){
9120             var dom = this.dom;
9121             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9122         },
9123
9124         /**
9125          * 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().
9126          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9127          * @param {Number} value The new scroll value
9128          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9129          * @return {Element} this
9130          */
9131
9132         scrollTo : function(side, value, animate){
9133             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9134             if(!animate || !A){
9135                 this.dom[prop] = value;
9136             }else{
9137                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9138                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9139             }
9140             return this;
9141         },
9142
9143         /**
9144          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9145          * within this element's scrollable range.
9146          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9147          * @param {Number} distance How far to scroll the element in pixels
9148          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9149          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9150          * was scrolled as far as it could go.
9151          */
9152          scroll : function(direction, distance, animate){
9153              if(!this.isScrollable()){
9154                  return;
9155              }
9156              var el = this.dom;
9157              var l = el.scrollLeft, t = el.scrollTop;
9158              var w = el.scrollWidth, h = el.scrollHeight;
9159              var cw = el.clientWidth, ch = el.clientHeight;
9160              direction = direction.toLowerCase();
9161              var scrolled = false;
9162              var a = this.preanim(arguments, 2);
9163              switch(direction){
9164                  case "l":
9165                  case "left":
9166                      if(w - l > cw){
9167                          var v = Math.min(l + distance, w-cw);
9168                          this.scrollTo("left", v, a);
9169                          scrolled = true;
9170                      }
9171                      break;
9172                 case "r":
9173                 case "right":
9174                      if(l > 0){
9175                          var v = Math.max(l - distance, 0);
9176                          this.scrollTo("left", v, a);
9177                          scrolled = true;
9178                      }
9179                      break;
9180                 case "t":
9181                 case "top":
9182                 case "up":
9183                      if(t > 0){
9184                          var v = Math.max(t - distance, 0);
9185                          this.scrollTo("top", v, a);
9186                          scrolled = true;
9187                      }
9188                      break;
9189                 case "b":
9190                 case "bottom":
9191                 case "down":
9192                      if(h - t > ch){
9193                          var v = Math.min(t + distance, h-ch);
9194                          this.scrollTo("top", v, a);
9195                          scrolled = true;
9196                      }
9197                      break;
9198              }
9199              return scrolled;
9200         },
9201
9202         /**
9203          * Translates the passed page coordinates into left/top css values for this element
9204          * @param {Number/Array} x The page x or an array containing [x, y]
9205          * @param {Number} y The page y
9206          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9207          */
9208         translatePoints : function(x, y){
9209             if(typeof x == 'object' || x instanceof Array){
9210                 y = x[1]; x = x[0];
9211             }
9212             var p = this.getStyle('position');
9213             var o = this.getXY();
9214
9215             var l = parseInt(this.getStyle('left'), 10);
9216             var t = parseInt(this.getStyle('top'), 10);
9217
9218             if(isNaN(l)){
9219                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9220             }
9221             if(isNaN(t)){
9222                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9223             }
9224
9225             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9226         },
9227
9228         /**
9229          * Returns the current scroll position of the element.
9230          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9231          */
9232         getScroll : function(){
9233             var d = this.dom, doc = document;
9234             if(d == doc || d == doc.body){
9235                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9236                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9237                 return {left: l, top: t};
9238             }else{
9239                 return {left: d.scrollLeft, top: d.scrollTop};
9240             }
9241         },
9242
9243         /**
9244          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9245          * are convert to standard 6 digit hex color.
9246          * @param {String} attr The css attribute
9247          * @param {String} defaultValue The default value to use when a valid color isn't found
9248          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9249          * YUI color anims.
9250          */
9251         getColor : function(attr, defaultValue, prefix){
9252             var v = this.getStyle(attr);
9253             if(!v || v == "transparent" || v == "inherit") {
9254                 return defaultValue;
9255             }
9256             var color = typeof prefix == "undefined" ? "#" : prefix;
9257             if(v.substr(0, 4) == "rgb("){
9258                 var rvs = v.slice(4, v.length -1).split(",");
9259                 for(var i = 0; i < 3; i++){
9260                     var h = parseInt(rvs[i]).toString(16);
9261                     if(h < 16){
9262                         h = "0" + h;
9263                     }
9264                     color += h;
9265                 }
9266             } else {
9267                 if(v.substr(0, 1) == "#"){
9268                     if(v.length == 4) {
9269                         for(var i = 1; i < 4; i++){
9270                             var c = v.charAt(i);
9271                             color +=  c + c;
9272                         }
9273                     }else if(v.length == 7){
9274                         color += v.substr(1);
9275                     }
9276                 }
9277             }
9278             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9279         },
9280
9281         /**
9282          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9283          * gradient background, rounded corners and a 4-way shadow.
9284          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9285          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9286          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9287          * @return {Roo.Element} this
9288          */
9289         boxWrap : function(cls){
9290             cls = cls || 'x-box';
9291             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9292             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9293             return el;
9294         },
9295
9296         /**
9297          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9298          * @param {String} namespace The namespace in which to look for the attribute
9299          * @param {String} name The attribute name
9300          * @return {String} The attribute value
9301          */
9302         getAttributeNS : Roo.isIE ? function(ns, name){
9303             var d = this.dom;
9304             var type = typeof d[ns+":"+name];
9305             if(type != 'undefined' && type != 'unknown'){
9306                 return d[ns+":"+name];
9307             }
9308             return d[name];
9309         } : function(ns, name){
9310             var d = this.dom;
9311             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9312         }
9313     };
9314
9315     var ep = El.prototype;
9316
9317     /**
9318      * Appends an event handler (Shorthand for addListener)
9319      * @param {String}   eventName     The type of event to append
9320      * @param {Function} fn        The method the event invokes
9321      * @param {Object} scope       (optional) The scope (this object) of the fn
9322      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9323      * @method
9324      */
9325     ep.on = ep.addListener;
9326         // backwards compat
9327     ep.mon = ep.addListener;
9328
9329     /**
9330      * Removes an event handler from this element (shorthand for removeListener)
9331      * @param {String} eventName the type of event to remove
9332      * @param {Function} fn the method the event invokes
9333      * @return {Roo.Element} this
9334      * @method
9335      */
9336     ep.un = ep.removeListener;
9337
9338     /**
9339      * true to automatically adjust width and height settings for box-model issues (default to true)
9340      */
9341     ep.autoBoxAdjust = true;
9342
9343     // private
9344     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9345
9346     // private
9347     El.addUnits = function(v, defaultUnit){
9348         if(v === "" || v == "auto"){
9349             return v;
9350         }
9351         if(v === undefined){
9352             return '';
9353         }
9354         if(typeof v == "number" || !El.unitPattern.test(v)){
9355             return v + (defaultUnit || 'px');
9356         }
9357         return v;
9358     };
9359
9360     // special markup used throughout Roo when box wrapping elements
9361     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>';
9362     /**
9363      * Visibility mode constant - Use visibility to hide element
9364      * @static
9365      * @type Number
9366      */
9367     El.VISIBILITY = 1;
9368     /**
9369      * Visibility mode constant - Use display to hide element
9370      * @static
9371      * @type Number
9372      */
9373     El.DISPLAY = 2;
9374
9375     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9376     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9377     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9378
9379
9380
9381     /**
9382      * @private
9383      */
9384     El.cache = {};
9385
9386     var docEl;
9387
9388     /**
9389      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9390      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9391      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9392      * @return {Element} The Element object
9393      * @static
9394      */
9395     El.get = function(el){
9396         var ex, elm, id;
9397         if(!el){ return null; }
9398         if(typeof el == "string"){ // element id
9399             if(!(elm = document.getElementById(el))){
9400                 return null;
9401             }
9402             if(ex = El.cache[el]){
9403                 ex.dom = elm;
9404             }else{
9405                 ex = El.cache[el] = new El(elm);
9406             }
9407             return ex;
9408         }else if(el.tagName){ // dom element
9409             if(!(id = el.id)){
9410                 id = Roo.id(el);
9411             }
9412             if(ex = El.cache[id]){
9413                 ex.dom = el;
9414             }else{
9415                 ex = El.cache[id] = new El(el);
9416             }
9417             return ex;
9418         }else if(el instanceof El){
9419             if(el != docEl){
9420                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9421                                                               // catch case where it hasn't been appended
9422                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9423             }
9424             return el;
9425         }else if(el.isComposite){
9426             return el;
9427         }else if(el instanceof Array){
9428             return El.select(el);
9429         }else if(el == document){
9430             // create a bogus element object representing the document object
9431             if(!docEl){
9432                 var f = function(){};
9433                 f.prototype = El.prototype;
9434                 docEl = new f();
9435                 docEl.dom = document;
9436             }
9437             return docEl;
9438         }
9439         return null;
9440     };
9441
9442     // private
9443     El.uncache = function(el){
9444         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9445             if(a[i]){
9446                 delete El.cache[a[i].id || a[i]];
9447             }
9448         }
9449     };
9450
9451     // private
9452     // Garbage collection - uncache elements/purge listeners on orphaned elements
9453     // so we don't hold a reference and cause the browser to retain them
9454     El.garbageCollect = function(){
9455         if(!Roo.enableGarbageCollector){
9456             clearInterval(El.collectorThread);
9457             return;
9458         }
9459         for(var eid in El.cache){
9460             var el = El.cache[eid], d = el.dom;
9461             // -------------------------------------------------------
9462             // Determining what is garbage:
9463             // -------------------------------------------------------
9464             // !d
9465             // dom node is null, definitely garbage
9466             // -------------------------------------------------------
9467             // !d.parentNode
9468             // no parentNode == direct orphan, definitely garbage
9469             // -------------------------------------------------------
9470             // !d.offsetParent && !document.getElementById(eid)
9471             // display none elements have no offsetParent so we will
9472             // also try to look it up by it's id. However, check
9473             // offsetParent first so we don't do unneeded lookups.
9474             // This enables collection of elements that are not orphans
9475             // directly, but somewhere up the line they have an orphan
9476             // parent.
9477             // -------------------------------------------------------
9478             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9479                 delete El.cache[eid];
9480                 if(d && Roo.enableListenerCollection){
9481                     E.purgeElement(d);
9482                 }
9483             }
9484         }
9485     }
9486     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9487
9488
9489     // dom is optional
9490     El.Flyweight = function(dom){
9491         this.dom = dom;
9492     };
9493     El.Flyweight.prototype = El.prototype;
9494
9495     El._flyweights = {};
9496     /**
9497      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9498      * the dom node can be overwritten by other code.
9499      * @param {String/HTMLElement} el The dom node or id
9500      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9501      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9502      * @static
9503      * @return {Element} The shared Element object
9504      */
9505     El.fly = function(el, named){
9506         named = named || '_global';
9507         el = Roo.getDom(el);
9508         if(!el){
9509             return null;
9510         }
9511         if(!El._flyweights[named]){
9512             El._flyweights[named] = new El.Flyweight();
9513         }
9514         El._flyweights[named].dom = el;
9515         return El._flyweights[named];
9516     };
9517
9518     /**
9519      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9520      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9521      * Shorthand of {@link Roo.Element#get}
9522      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9523      * @return {Element} The Element object
9524      * @member Roo
9525      * @method get
9526      */
9527     Roo.get = El.get;
9528     /**
9529      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9530      * the dom node can be overwritten by other code.
9531      * Shorthand of {@link Roo.Element#fly}
9532      * @param {String/HTMLElement} el The dom node or id
9533      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9534      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9535      * @static
9536      * @return {Element} The shared Element object
9537      * @member Roo
9538      * @method fly
9539      */
9540     Roo.fly = El.fly;
9541
9542     // speedy lookup for elements never to box adjust
9543     var noBoxAdjust = Roo.isStrict ? {
9544         select:1
9545     } : {
9546         input:1, select:1, textarea:1
9547     };
9548     if(Roo.isIE || Roo.isGecko){
9549         noBoxAdjust['button'] = 1;
9550     }
9551
9552
9553     Roo.EventManager.on(window, 'unload', function(){
9554         delete El.cache;
9555         delete El._flyweights;
9556     });
9557 })();
9558
9559
9560
9561
9562 if(Roo.DomQuery){
9563     Roo.Element.selectorFunction = Roo.DomQuery.select;
9564 }
9565
9566 Roo.Element.select = function(selector, unique, root){
9567     var els;
9568     if(typeof selector == "string"){
9569         els = Roo.Element.selectorFunction(selector, root);
9570     }else if(selector.length !== undefined){
9571         els = selector;
9572     }else{
9573         throw "Invalid selector";
9574     }
9575     if(unique === true){
9576         return new Roo.CompositeElement(els);
9577     }else{
9578         return new Roo.CompositeElementLite(els);
9579     }
9580 };
9581 /**
9582  * Selects elements based on the passed CSS selector to enable working on them as 1.
9583  * @param {String/Array} selector The CSS selector or an array of elements
9584  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9585  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9586  * @return {CompositeElementLite/CompositeElement}
9587  * @member Roo
9588  * @method select
9589  */
9590 Roo.select = Roo.Element.select;
9591
9592
9593
9594
9595
9596
9597
9598
9599
9600
9601
9602
9603
9604
9605 /*
9606  * Based on:
9607  * Ext JS Library 1.1.1
9608  * Copyright(c) 2006-2007, Ext JS, LLC.
9609  *
9610  * Originally Released Under LGPL - original licence link has changed is not relivant.
9611  *
9612  * Fork - LGPL
9613  * <script type="text/javascript">
9614  */
9615
9616
9617
9618 //Notifies Element that fx methods are available
9619 Roo.enableFx = true;
9620
9621 /**
9622  * @class Roo.Fx
9623  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9624  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9625  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9626  * Element effects to work.</p><br/>
9627  *
9628  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9629  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9630  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9631  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9632  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9633  * expected results and should be done with care.</p><br/>
9634  *
9635  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9636  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9637 <pre>
9638 Value  Description
9639 -----  -----------------------------
9640 tl     The top left corner
9641 t      The center of the top edge
9642 tr     The top right corner
9643 l      The center of the left edge
9644 r      The center of the right edge
9645 bl     The bottom left corner
9646 b      The center of the bottom edge
9647 br     The bottom right corner
9648 </pre>
9649  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9650  * below are common options that can be passed to any Fx method.</b>
9651  * @cfg {Function} callback A function called when the effect is finished
9652  * @cfg {Object} scope The scope of the effect function
9653  * @cfg {String} easing A valid Easing value for the effect
9654  * @cfg {String} afterCls A css class to apply after the effect
9655  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9656  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9657  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9658  * effects that end with the element being visually hidden, ignored otherwise)
9659  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9660  * a function which returns such a specification that will be applied to the Element after the effect finishes
9661  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9662  * @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
9663  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9664  */
9665 Roo.Fx = {
9666         /**
9667          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9668          * origin for the slide effect.  This function automatically handles wrapping the element with
9669          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9670          * Usage:
9671          *<pre><code>
9672 // default: slide the element in from the top
9673 el.slideIn();
9674
9675 // custom: slide the element in from the right with a 2-second duration
9676 el.slideIn('r', { duration: 2 });
9677
9678 // common config options shown with default values
9679 el.slideIn('t', {
9680     easing: 'easeOut',
9681     duration: .5
9682 });
9683 </code></pre>
9684          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9685          * @param {Object} options (optional) Object literal with any of the Fx config options
9686          * @return {Roo.Element} The Element
9687          */
9688     slideIn : function(anchor, o){
9689         var el = this.getFxEl();
9690         o = o || {};
9691
9692         el.queueFx(o, function(){
9693
9694             anchor = anchor || "t";
9695
9696             // fix display to visibility
9697             this.fixDisplay();
9698
9699             // restore values after effect
9700             var r = this.getFxRestore();
9701             var b = this.getBox();
9702             // fixed size for slide
9703             this.setSize(b);
9704
9705             // wrap if needed
9706             var wrap = this.fxWrap(r.pos, o, "hidden");
9707
9708             var st = this.dom.style;
9709             st.visibility = "visible";
9710             st.position = "absolute";
9711
9712             // clear out temp styles after slide and unwrap
9713             var after = function(){
9714                 el.fxUnwrap(wrap, r.pos, o);
9715                 st.width = r.width;
9716                 st.height = r.height;
9717                 el.afterFx(o);
9718             };
9719             // time to calc the positions
9720             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9721
9722             switch(anchor.toLowerCase()){
9723                 case "t":
9724                     wrap.setSize(b.width, 0);
9725                     st.left = st.bottom = "0";
9726                     a = {height: bh};
9727                 break;
9728                 case "l":
9729                     wrap.setSize(0, b.height);
9730                     st.right = st.top = "0";
9731                     a = {width: bw};
9732                 break;
9733                 case "r":
9734                     wrap.setSize(0, b.height);
9735                     wrap.setX(b.right);
9736                     st.left = st.top = "0";
9737                     a = {width: bw, points: pt};
9738                 break;
9739                 case "b":
9740                     wrap.setSize(b.width, 0);
9741                     wrap.setY(b.bottom);
9742                     st.left = st.top = "0";
9743                     a = {height: bh, points: pt};
9744                 break;
9745                 case "tl":
9746                     wrap.setSize(0, 0);
9747                     st.right = st.bottom = "0";
9748                     a = {width: bw, height: bh};
9749                 break;
9750                 case "bl":
9751                     wrap.setSize(0, 0);
9752                     wrap.setY(b.y+b.height);
9753                     st.right = st.top = "0";
9754                     a = {width: bw, height: bh, points: pt};
9755                 break;
9756                 case "br":
9757                     wrap.setSize(0, 0);
9758                     wrap.setXY([b.right, b.bottom]);
9759                     st.left = st.top = "0";
9760                     a = {width: bw, height: bh, points: pt};
9761                 break;
9762                 case "tr":
9763                     wrap.setSize(0, 0);
9764                     wrap.setX(b.x+b.width);
9765                     st.left = st.bottom = "0";
9766                     a = {width: bw, height: bh, points: pt};
9767                 break;
9768             }
9769             this.dom.style.visibility = "visible";
9770             wrap.show();
9771
9772             arguments.callee.anim = wrap.fxanim(a,
9773                 o,
9774                 'motion',
9775                 .5,
9776                 'easeOut', after);
9777         });
9778         return this;
9779     },
9780     
9781         /**
9782          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9783          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9784          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9785          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9786          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9787          * Usage:
9788          *<pre><code>
9789 // default: slide the element out to the top
9790 el.slideOut();
9791
9792 // custom: slide the element out to the right with a 2-second duration
9793 el.slideOut('r', { duration: 2 });
9794
9795 // common config options shown with default values
9796 el.slideOut('t', {
9797     easing: 'easeOut',
9798     duration: .5,
9799     remove: false,
9800     useDisplay: false
9801 });
9802 </code></pre>
9803          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9804          * @param {Object} options (optional) Object literal with any of the Fx config options
9805          * @return {Roo.Element} The Element
9806          */
9807     slideOut : function(anchor, o){
9808         var el = this.getFxEl();
9809         o = o || {};
9810
9811         el.queueFx(o, function(){
9812
9813             anchor = anchor || "t";
9814
9815             // restore values after effect
9816             var r = this.getFxRestore();
9817             
9818             var b = this.getBox();
9819             // fixed size for slide
9820             this.setSize(b);
9821
9822             // wrap if needed
9823             var wrap = this.fxWrap(r.pos, o, "visible");
9824
9825             var st = this.dom.style;
9826             st.visibility = "visible";
9827             st.position = "absolute";
9828
9829             wrap.setSize(b);
9830
9831             var after = function(){
9832                 if(o.useDisplay){
9833                     el.setDisplayed(false);
9834                 }else{
9835                     el.hide();
9836                 }
9837
9838                 el.fxUnwrap(wrap, r.pos, o);
9839
9840                 st.width = r.width;
9841                 st.height = r.height;
9842
9843                 el.afterFx(o);
9844             };
9845
9846             var a, zero = {to: 0};
9847             switch(anchor.toLowerCase()){
9848                 case "t":
9849                     st.left = st.bottom = "0";
9850                     a = {height: zero};
9851                 break;
9852                 case "l":
9853                     st.right = st.top = "0";
9854                     a = {width: zero};
9855                 break;
9856                 case "r":
9857                     st.left = st.top = "0";
9858                     a = {width: zero, points: {to:[b.right, b.y]}};
9859                 break;
9860                 case "b":
9861                     st.left = st.top = "0";
9862                     a = {height: zero, points: {to:[b.x, b.bottom]}};
9863                 break;
9864                 case "tl":
9865                     st.right = st.bottom = "0";
9866                     a = {width: zero, height: zero};
9867                 break;
9868                 case "bl":
9869                     st.right = st.top = "0";
9870                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9871                 break;
9872                 case "br":
9873                     st.left = st.top = "0";
9874                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9875                 break;
9876                 case "tr":
9877                     st.left = st.bottom = "0";
9878                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9879                 break;
9880             }
9881
9882             arguments.callee.anim = wrap.fxanim(a,
9883                 o,
9884                 'motion',
9885                 .5,
9886                 "easeOut", after);
9887         });
9888         return this;
9889     },
9890
9891         /**
9892          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
9893          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
9894          * The element must be removed from the DOM using the 'remove' config option if desired.
9895          * Usage:
9896          *<pre><code>
9897 // default
9898 el.puff();
9899
9900 // common config options shown with default values
9901 el.puff({
9902     easing: 'easeOut',
9903     duration: .5,
9904     remove: false,
9905     useDisplay: false
9906 });
9907 </code></pre>
9908          * @param {Object} options (optional) Object literal with any of the Fx config options
9909          * @return {Roo.Element} The Element
9910          */
9911     puff : function(o){
9912         var el = this.getFxEl();
9913         o = o || {};
9914
9915         el.queueFx(o, function(){
9916             this.clearOpacity();
9917             this.show();
9918
9919             // restore values after effect
9920             var r = this.getFxRestore();
9921             var st = this.dom.style;
9922
9923             var after = function(){
9924                 if(o.useDisplay){
9925                     el.setDisplayed(false);
9926                 }else{
9927                     el.hide();
9928                 }
9929
9930                 el.clearOpacity();
9931
9932                 el.setPositioning(r.pos);
9933                 st.width = r.width;
9934                 st.height = r.height;
9935                 st.fontSize = '';
9936                 el.afterFx(o);
9937             };
9938
9939             var width = this.getWidth();
9940             var height = this.getHeight();
9941
9942             arguments.callee.anim = this.fxanim({
9943                     width : {to: this.adjustWidth(width * 2)},
9944                     height : {to: this.adjustHeight(height * 2)},
9945                     points : {by: [-(width * .5), -(height * .5)]},
9946                     opacity : {to: 0},
9947                     fontSize: {to:200, unit: "%"}
9948                 },
9949                 o,
9950                 'motion',
9951                 .5,
9952                 "easeOut", after);
9953         });
9954         return this;
9955     },
9956
9957         /**
9958          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9959          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
9960          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9961          * Usage:
9962          *<pre><code>
9963 // default
9964 el.switchOff();
9965
9966 // all config options shown with default values
9967 el.switchOff({
9968     easing: 'easeIn',
9969     duration: .3,
9970     remove: false,
9971     useDisplay: false
9972 });
9973 </code></pre>
9974          * @param {Object} options (optional) Object literal with any of the Fx config options
9975          * @return {Roo.Element} The Element
9976          */
9977     switchOff : function(o){
9978         var el = this.getFxEl();
9979         o = o || {};
9980
9981         el.queueFx(o, function(){
9982             this.clearOpacity();
9983             this.clip();
9984
9985             // restore values after effect
9986             var r = this.getFxRestore();
9987             var st = this.dom.style;
9988
9989             var after = function(){
9990                 if(o.useDisplay){
9991                     el.setDisplayed(false);
9992                 }else{
9993                     el.hide();
9994                 }
9995
9996                 el.clearOpacity();
9997                 el.setPositioning(r.pos);
9998                 st.width = r.width;
9999                 st.height = r.height;
10000
10001                 el.afterFx(o);
10002             };
10003
10004             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10005                 this.clearOpacity();
10006                 (function(){
10007                     this.fxanim({
10008                         height:{to:1},
10009                         points:{by:[0, this.getHeight() * .5]}
10010                     }, o, 'motion', 0.3, 'easeIn', after);
10011                 }).defer(100, this);
10012             });
10013         });
10014         return this;
10015     },
10016
10017     /**
10018      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10019      * changed using the "attr" config option) and then fading back to the original color. If no original
10020      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10021      * Usage:
10022 <pre><code>
10023 // default: highlight background to yellow
10024 el.highlight();
10025
10026 // custom: highlight foreground text to blue for 2 seconds
10027 el.highlight("0000ff", { attr: 'color', duration: 2 });
10028
10029 // common config options shown with default values
10030 el.highlight("ffff9c", {
10031     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10032     endColor: (current color) or "ffffff",
10033     easing: 'easeIn',
10034     duration: 1
10035 });
10036 </code></pre>
10037      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10038      * @param {Object} options (optional) Object literal with any of the Fx config options
10039      * @return {Roo.Element} The Element
10040      */ 
10041     highlight : function(color, o){
10042         var el = this.getFxEl();
10043         o = o || {};
10044
10045         el.queueFx(o, function(){
10046             color = color || "ffff9c";
10047             attr = o.attr || "backgroundColor";
10048
10049             this.clearOpacity();
10050             this.show();
10051
10052             var origColor = this.getColor(attr);
10053             var restoreColor = this.dom.style[attr];
10054             endColor = (o.endColor || origColor) || "ffffff";
10055
10056             var after = function(){
10057                 el.dom.style[attr] = restoreColor;
10058                 el.afterFx(o);
10059             };
10060
10061             var a = {};
10062             a[attr] = {from: color, to: endColor};
10063             arguments.callee.anim = this.fxanim(a,
10064                 o,
10065                 'color',
10066                 1,
10067                 'easeIn', after);
10068         });
10069         return this;
10070     },
10071
10072    /**
10073     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10074     * Usage:
10075 <pre><code>
10076 // default: a single light blue ripple
10077 el.frame();
10078
10079 // custom: 3 red ripples lasting 3 seconds total
10080 el.frame("ff0000", 3, { duration: 3 });
10081
10082 // common config options shown with default values
10083 el.frame("C3DAF9", 1, {
10084     duration: 1 //duration of entire animation (not each individual ripple)
10085     // Note: Easing is not configurable and will be ignored if included
10086 });
10087 </code></pre>
10088     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10089     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10090     * @param {Object} options (optional) Object literal with any of the Fx config options
10091     * @return {Roo.Element} The Element
10092     */
10093     frame : function(color, count, o){
10094         var el = this.getFxEl();
10095         o = o || {};
10096
10097         el.queueFx(o, function(){
10098             color = color || "#C3DAF9";
10099             if(color.length == 6){
10100                 color = "#" + color;
10101             }
10102             count = count || 1;
10103             duration = o.duration || 1;
10104             this.show();
10105
10106             var b = this.getBox();
10107             var animFn = function(){
10108                 var proxy = this.createProxy({
10109
10110                      style:{
10111                         visbility:"hidden",
10112                         position:"absolute",
10113                         "z-index":"35000", // yee haw
10114                         border:"0px solid " + color
10115                      }
10116                   });
10117                 var scale = Roo.isBorderBox ? 2 : 1;
10118                 proxy.animate({
10119                     top:{from:b.y, to:b.y - 20},
10120                     left:{from:b.x, to:b.x - 20},
10121                     borderWidth:{from:0, to:10},
10122                     opacity:{from:1, to:0},
10123                     height:{from:b.height, to:(b.height + (20*scale))},
10124                     width:{from:b.width, to:(b.width + (20*scale))}
10125                 }, duration, function(){
10126                     proxy.remove();
10127                 });
10128                 if(--count > 0){
10129                      animFn.defer((duration/2)*1000, this);
10130                 }else{
10131                     el.afterFx(o);
10132                 }
10133             };
10134             animFn.call(this);
10135         });
10136         return this;
10137     },
10138
10139    /**
10140     * Creates a pause before any subsequent queued effects begin.  If there are
10141     * no effects queued after the pause it will have no effect.
10142     * Usage:
10143 <pre><code>
10144 el.pause(1);
10145 </code></pre>
10146     * @param {Number} seconds The length of time to pause (in seconds)
10147     * @return {Roo.Element} The Element
10148     */
10149     pause : function(seconds){
10150         var el = this.getFxEl();
10151         var o = {};
10152
10153         el.queueFx(o, function(){
10154             setTimeout(function(){
10155                 el.afterFx(o);
10156             }, seconds * 1000);
10157         });
10158         return this;
10159     },
10160
10161    /**
10162     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10163     * using the "endOpacity" config option.
10164     * Usage:
10165 <pre><code>
10166 // default: fade in from opacity 0 to 100%
10167 el.fadeIn();
10168
10169 // custom: fade in from opacity 0 to 75% over 2 seconds
10170 el.fadeIn({ endOpacity: .75, duration: 2});
10171
10172 // common config options shown with default values
10173 el.fadeIn({
10174     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10175     easing: 'easeOut',
10176     duration: .5
10177 });
10178 </code></pre>
10179     * @param {Object} options (optional) Object literal with any of the Fx config options
10180     * @return {Roo.Element} The Element
10181     */
10182     fadeIn : function(o){
10183         var el = this.getFxEl();
10184         o = o || {};
10185         el.queueFx(o, function(){
10186             this.setOpacity(0);
10187             this.fixDisplay();
10188             this.dom.style.visibility = 'visible';
10189             var to = o.endOpacity || 1;
10190             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10191                 o, null, .5, "easeOut", function(){
10192                 if(to == 1){
10193                     this.clearOpacity();
10194                 }
10195                 el.afterFx(o);
10196             });
10197         });
10198         return this;
10199     },
10200
10201    /**
10202     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10203     * using the "endOpacity" config option.
10204     * Usage:
10205 <pre><code>
10206 // default: fade out from the element's current opacity to 0
10207 el.fadeOut();
10208
10209 // custom: fade out from the element's current opacity to 25% over 2 seconds
10210 el.fadeOut({ endOpacity: .25, duration: 2});
10211
10212 // common config options shown with default values
10213 el.fadeOut({
10214     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10215     easing: 'easeOut',
10216     duration: .5
10217     remove: false,
10218     useDisplay: false
10219 });
10220 </code></pre>
10221     * @param {Object} options (optional) Object literal with any of the Fx config options
10222     * @return {Roo.Element} The Element
10223     */
10224     fadeOut : function(o){
10225         var el = this.getFxEl();
10226         o = o || {};
10227         el.queueFx(o, function(){
10228             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10229                 o, null, .5, "easeOut", function(){
10230                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10231                      this.dom.style.display = "none";
10232                 }else{
10233                      this.dom.style.visibility = "hidden";
10234                 }
10235                 this.clearOpacity();
10236                 el.afterFx(o);
10237             });
10238         });
10239         return this;
10240     },
10241
10242    /**
10243     * Animates the transition of an element's dimensions from a starting height/width
10244     * to an ending height/width.
10245     * Usage:
10246 <pre><code>
10247 // change height and width to 100x100 pixels
10248 el.scale(100, 100);
10249
10250 // common config options shown with default values.  The height and width will default to
10251 // the element's existing values if passed as null.
10252 el.scale(
10253     [element's width],
10254     [element's height], {
10255     easing: 'easeOut',
10256     duration: .35
10257 });
10258 </code></pre>
10259     * @param {Number} width  The new width (pass undefined to keep the original width)
10260     * @param {Number} height  The new height (pass undefined to keep the original height)
10261     * @param {Object} options (optional) Object literal with any of the Fx config options
10262     * @return {Roo.Element} The Element
10263     */
10264     scale : function(w, h, o){
10265         this.shift(Roo.apply({}, o, {
10266             width: w,
10267             height: h
10268         }));
10269         return this;
10270     },
10271
10272    /**
10273     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10274     * Any of these properties not specified in the config object will not be changed.  This effect 
10275     * requires that at least one new dimension, position or opacity setting must be passed in on
10276     * the config object in order for the function to have any effect.
10277     * Usage:
10278 <pre><code>
10279 // slide the element horizontally to x position 200 while changing the height and opacity
10280 el.shift({ x: 200, height: 50, opacity: .8 });
10281
10282 // common config options shown with default values.
10283 el.shift({
10284     width: [element's width],
10285     height: [element's height],
10286     x: [element's x position],
10287     y: [element's y position],
10288     opacity: [element's opacity],
10289     easing: 'easeOut',
10290     duration: .35
10291 });
10292 </code></pre>
10293     * @param {Object} options  Object literal with any of the Fx config options
10294     * @return {Roo.Element} The Element
10295     */
10296     shift : function(o){
10297         var el = this.getFxEl();
10298         o = o || {};
10299         el.queueFx(o, function(){
10300             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10301             if(w !== undefined){
10302                 a.width = {to: this.adjustWidth(w)};
10303             }
10304             if(h !== undefined){
10305                 a.height = {to: this.adjustHeight(h)};
10306             }
10307             if(x !== undefined || y !== undefined){
10308                 a.points = {to: [
10309                     x !== undefined ? x : this.getX(),
10310                     y !== undefined ? y : this.getY()
10311                 ]};
10312             }
10313             if(op !== undefined){
10314                 a.opacity = {to: op};
10315             }
10316             if(o.xy !== undefined){
10317                 a.points = {to: o.xy};
10318             }
10319             arguments.callee.anim = this.fxanim(a,
10320                 o, 'motion', .35, "easeOut", function(){
10321                 el.afterFx(o);
10322             });
10323         });
10324         return this;
10325     },
10326
10327         /**
10328          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10329          * ending point of the effect.
10330          * Usage:
10331          *<pre><code>
10332 // default: slide the element downward while fading out
10333 el.ghost();
10334
10335 // custom: slide the element out to the right with a 2-second duration
10336 el.ghost('r', { duration: 2 });
10337
10338 // common config options shown with default values
10339 el.ghost('b', {
10340     easing: 'easeOut',
10341     duration: .5
10342     remove: false,
10343     useDisplay: false
10344 });
10345 </code></pre>
10346          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10347          * @param {Object} options (optional) Object literal with any of the Fx config options
10348          * @return {Roo.Element} The Element
10349          */
10350     ghost : function(anchor, o){
10351         var el = this.getFxEl();
10352         o = o || {};
10353
10354         el.queueFx(o, function(){
10355             anchor = anchor || "b";
10356
10357             // restore values after effect
10358             var r = this.getFxRestore();
10359             var w = this.getWidth(),
10360                 h = this.getHeight();
10361
10362             var st = this.dom.style;
10363
10364             var after = function(){
10365                 if(o.useDisplay){
10366                     el.setDisplayed(false);
10367                 }else{
10368                     el.hide();
10369                 }
10370
10371                 el.clearOpacity();
10372                 el.setPositioning(r.pos);
10373                 st.width = r.width;
10374                 st.height = r.height;
10375
10376                 el.afterFx(o);
10377             };
10378
10379             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10380             switch(anchor.toLowerCase()){
10381                 case "t":
10382                     pt.by = [0, -h];
10383                 break;
10384                 case "l":
10385                     pt.by = [-w, 0];
10386                 break;
10387                 case "r":
10388                     pt.by = [w, 0];
10389                 break;
10390                 case "b":
10391                     pt.by = [0, h];
10392                 break;
10393                 case "tl":
10394                     pt.by = [-w, -h];
10395                 break;
10396                 case "bl":
10397                     pt.by = [-w, h];
10398                 break;
10399                 case "br":
10400                     pt.by = [w, h];
10401                 break;
10402                 case "tr":
10403                     pt.by = [w, -h];
10404                 break;
10405             }
10406
10407             arguments.callee.anim = this.fxanim(a,
10408                 o,
10409                 'motion',
10410                 .5,
10411                 "easeOut", after);
10412         });
10413         return this;
10414     },
10415
10416         /**
10417          * Ensures that all effects queued after syncFx is called on the element are
10418          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10419          * @return {Roo.Element} The Element
10420          */
10421     syncFx : function(){
10422         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10423             block : false,
10424             concurrent : true,
10425             stopFx : false
10426         });
10427         return this;
10428     },
10429
10430         /**
10431          * Ensures that all effects queued after sequenceFx is called on the element are
10432          * run in sequence.  This is the opposite of {@link #syncFx}.
10433          * @return {Roo.Element} The Element
10434          */
10435     sequenceFx : function(){
10436         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10437             block : false,
10438             concurrent : false,
10439             stopFx : false
10440         });
10441         return this;
10442     },
10443
10444         /* @private */
10445     nextFx : function(){
10446         var ef = this.fxQueue[0];
10447         if(ef){
10448             ef.call(this);
10449         }
10450     },
10451
10452         /**
10453          * Returns true if the element has any effects actively running or queued, else returns false.
10454          * @return {Boolean} True if element has active effects, else false
10455          */
10456     hasActiveFx : function(){
10457         return this.fxQueue && this.fxQueue[0];
10458     },
10459
10460         /**
10461          * Stops any running effects and clears the element's internal effects queue if it contains
10462          * any additional effects that haven't started yet.
10463          * @return {Roo.Element} The Element
10464          */
10465     stopFx : function(){
10466         if(this.hasActiveFx()){
10467             var cur = this.fxQueue[0];
10468             if(cur && cur.anim && cur.anim.isAnimated()){
10469                 this.fxQueue = [cur]; // clear out others
10470                 cur.anim.stop(true);
10471             }
10472         }
10473         return this;
10474     },
10475
10476         /* @private */
10477     beforeFx : function(o){
10478         if(this.hasActiveFx() && !o.concurrent){
10479            if(o.stopFx){
10480                this.stopFx();
10481                return true;
10482            }
10483            return false;
10484         }
10485         return true;
10486     },
10487
10488         /**
10489          * Returns true if the element is currently blocking so that no other effect can be queued
10490          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10491          * used to ensure that an effect initiated by a user action runs to completion prior to the
10492          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10493          * @return {Boolean} True if blocking, else false
10494          */
10495     hasFxBlock : function(){
10496         var q = this.fxQueue;
10497         return q && q[0] && q[0].block;
10498     },
10499
10500         /* @private */
10501     queueFx : function(o, fn){
10502         if(!this.fxQueue){
10503             this.fxQueue = [];
10504         }
10505         if(!this.hasFxBlock()){
10506             Roo.applyIf(o, this.fxDefaults);
10507             if(!o.concurrent){
10508                 var run = this.beforeFx(o);
10509                 fn.block = o.block;
10510                 this.fxQueue.push(fn);
10511                 if(run){
10512                     this.nextFx();
10513                 }
10514             }else{
10515                 fn.call(this);
10516             }
10517         }
10518         return this;
10519     },
10520
10521         /* @private */
10522     fxWrap : function(pos, o, vis){
10523         var wrap;
10524         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10525             var wrapXY;
10526             if(o.fixPosition){
10527                 wrapXY = this.getXY();
10528             }
10529             var div = document.createElement("div");
10530             div.style.visibility = vis;
10531             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10532             wrap.setPositioning(pos);
10533             if(wrap.getStyle("position") == "static"){
10534                 wrap.position("relative");
10535             }
10536             this.clearPositioning('auto');
10537             wrap.clip();
10538             wrap.dom.appendChild(this.dom);
10539             if(wrapXY){
10540                 wrap.setXY(wrapXY);
10541             }
10542         }
10543         return wrap;
10544     },
10545
10546         /* @private */
10547     fxUnwrap : function(wrap, pos, o){
10548         this.clearPositioning();
10549         this.setPositioning(pos);
10550         if(!o.wrap){
10551             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10552             wrap.remove();
10553         }
10554     },
10555
10556         /* @private */
10557     getFxRestore : function(){
10558         var st = this.dom.style;
10559         return {pos: this.getPositioning(), width: st.width, height : st.height};
10560     },
10561
10562         /* @private */
10563     afterFx : function(o){
10564         if(o.afterStyle){
10565             this.applyStyles(o.afterStyle);
10566         }
10567         if(o.afterCls){
10568             this.addClass(o.afterCls);
10569         }
10570         if(o.remove === true){
10571             this.remove();
10572         }
10573         Roo.callback(o.callback, o.scope, [this]);
10574         if(!o.concurrent){
10575             this.fxQueue.shift();
10576             this.nextFx();
10577         }
10578     },
10579
10580         /* @private */
10581     getFxEl : function(){ // support for composite element fx
10582         return Roo.get(this.dom);
10583     },
10584
10585         /* @private */
10586     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10587         animType = animType || 'run';
10588         opt = opt || {};
10589         var anim = Roo.lib.Anim[animType](
10590             this.dom, args,
10591             (opt.duration || defaultDur) || .35,
10592             (opt.easing || defaultEase) || 'easeOut',
10593             function(){
10594                 Roo.callback(cb, this);
10595             },
10596             this
10597         );
10598         opt.anim = anim;
10599         return anim;
10600     }
10601 };
10602
10603 // backwords compat
10604 Roo.Fx.resize = Roo.Fx.scale;
10605
10606 //When included, Roo.Fx is automatically applied to Element so that all basic
10607 //effects are available directly via the Element API
10608 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10609  * Based on:
10610  * Ext JS Library 1.1.1
10611  * Copyright(c) 2006-2007, Ext JS, LLC.
10612  *
10613  * Originally Released Under LGPL - original licence link has changed is not relivant.
10614  *
10615  * Fork - LGPL
10616  * <script type="text/javascript">
10617  */
10618
10619
10620 /**
10621  * @class Roo.CompositeElement
10622  * Standard composite class. Creates a Roo.Element for every element in the collection.
10623  * <br><br>
10624  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10625  * actions will be performed on all the elements in this collection.</b>
10626  * <br><br>
10627  * All methods return <i>this</i> and can be chained.
10628  <pre><code>
10629  var els = Roo.select("#some-el div.some-class", true);
10630  // or select directly from an existing element
10631  var el = Roo.get('some-el');
10632  el.select('div.some-class', true);
10633
10634  els.setWidth(100); // all elements become 100 width
10635  els.hide(true); // all elements fade out and hide
10636  // or
10637  els.setWidth(100).hide(true);
10638  </code></pre>
10639  */
10640 Roo.CompositeElement = function(els){
10641     this.elements = [];
10642     this.addElements(els);
10643 };
10644 Roo.CompositeElement.prototype = {
10645     isComposite: true,
10646     addElements : function(els){
10647         if(!els) return this;
10648         if(typeof els == "string"){
10649             els = Roo.Element.selectorFunction(els);
10650         }
10651         var yels = this.elements;
10652         var index = yels.length-1;
10653         for(var i = 0, len = els.length; i < len; i++) {
10654                 yels[++index] = Roo.get(els[i]);
10655         }
10656         return this;
10657     },
10658
10659     /**
10660     * Clears this composite and adds the elements returned by the passed selector.
10661     * @param {String/Array} els A string CSS selector, an array of elements or an element
10662     * @return {CompositeElement} this
10663     */
10664     fill : function(els){
10665         this.elements = [];
10666         this.add(els);
10667         return this;
10668     },
10669
10670     /**
10671     * Filters this composite to only elements that match the passed selector.
10672     * @param {String} selector A string CSS selector
10673     * @return {CompositeElement} this
10674     */
10675     filter : function(selector){
10676         var els = [];
10677         this.each(function(el){
10678             if(el.is(selector)){
10679                 els[els.length] = el.dom;
10680             }
10681         });
10682         this.fill(els);
10683         return this;
10684     },
10685
10686     invoke : function(fn, args){
10687         var els = this.elements;
10688         for(var i = 0, len = els.length; i < len; i++) {
10689                 Roo.Element.prototype[fn].apply(els[i], args);
10690         }
10691         return this;
10692     },
10693     /**
10694     * Adds elements to this composite.
10695     * @param {String/Array} els A string CSS selector, an array of elements or an element
10696     * @return {CompositeElement} this
10697     */
10698     add : function(els){
10699         if(typeof els == "string"){
10700             this.addElements(Roo.Element.selectorFunction(els));
10701         }else if(els.length !== undefined){
10702             this.addElements(els);
10703         }else{
10704             this.addElements([els]);
10705         }
10706         return this;
10707     },
10708     /**
10709     * Calls the passed function passing (el, this, index) for each element in this composite.
10710     * @param {Function} fn The function to call
10711     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10712     * @return {CompositeElement} this
10713     */
10714     each : function(fn, scope){
10715         var els = this.elements;
10716         for(var i = 0, len = els.length; i < len; i++){
10717             if(fn.call(scope || els[i], els[i], this, i) === false) {
10718                 break;
10719             }
10720         }
10721         return this;
10722     },
10723
10724     /**
10725      * Returns the Element object at the specified index
10726      * @param {Number} index
10727      * @return {Roo.Element}
10728      */
10729     item : function(index){
10730         return this.elements[index] || null;
10731     },
10732
10733     /**
10734      * Returns the first Element
10735      * @return {Roo.Element}
10736      */
10737     first : function(){
10738         return this.item(0);
10739     },
10740
10741     /**
10742      * Returns the last Element
10743      * @return {Roo.Element}
10744      */
10745     last : function(){
10746         return this.item(this.elements.length-1);
10747     },
10748
10749     /**
10750      * Returns the number of elements in this composite
10751      * @return Number
10752      */
10753     getCount : function(){
10754         return this.elements.length;
10755     },
10756
10757     /**
10758      * Returns true if this composite contains the passed element
10759      * @return Boolean
10760      */
10761     contains : function(el){
10762         return this.indexOf(el) !== -1;
10763     },
10764
10765     /**
10766      * Returns true if this composite contains the passed element
10767      * @return Boolean
10768      */
10769     indexOf : function(el){
10770         return this.elements.indexOf(Roo.get(el));
10771     },
10772
10773
10774     /**
10775     * Removes the specified element(s).
10776     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10777     * or an array of any of those.
10778     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10779     * @return {CompositeElement} this
10780     */
10781     removeElement : function(el, removeDom){
10782         if(el instanceof Array){
10783             for(var i = 0, len = el.length; i < len; i++){
10784                 this.removeElement(el[i]);
10785             }
10786             return this;
10787         }
10788         var index = typeof el == 'number' ? el : this.indexOf(el);
10789         if(index !== -1){
10790             if(removeDom){
10791                 var d = this.elements[index];
10792                 if(d.dom){
10793                     d.remove();
10794                 }else{
10795                     d.parentNode.removeChild(d);
10796                 }
10797             }
10798             this.elements.splice(index, 1);
10799         }
10800         return this;
10801     },
10802
10803     /**
10804     * Replaces the specified element with the passed element.
10805     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10806     * to replace.
10807     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10808     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10809     * @return {CompositeElement} this
10810     */
10811     replaceElement : function(el, replacement, domReplace){
10812         var index = typeof el == 'number' ? el : this.indexOf(el);
10813         if(index !== -1){
10814             if(domReplace){
10815                 this.elements[index].replaceWith(replacement);
10816             }else{
10817                 this.elements.splice(index, 1, Roo.get(replacement))
10818             }
10819         }
10820         return this;
10821     },
10822
10823     /**
10824      * Removes all elements.
10825      */
10826     clear : function(){
10827         this.elements = [];
10828     }
10829 };
10830 (function(){
10831     Roo.CompositeElement.createCall = function(proto, fnName){
10832         if(!proto[fnName]){
10833             proto[fnName] = function(){
10834                 return this.invoke(fnName, arguments);
10835             };
10836         }
10837     };
10838     for(var fnName in Roo.Element.prototype){
10839         if(typeof Roo.Element.prototype[fnName] == "function"){
10840             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10841         }
10842     };
10843 })();
10844 /*
10845  * Based on:
10846  * Ext JS Library 1.1.1
10847  * Copyright(c) 2006-2007, Ext JS, LLC.
10848  *
10849  * Originally Released Under LGPL - original licence link has changed is not relivant.
10850  *
10851  * Fork - LGPL
10852  * <script type="text/javascript">
10853  */
10854
10855 /**
10856  * @class Roo.CompositeElementLite
10857  * @extends Roo.CompositeElement
10858  * Flyweight composite class. Reuses the same Roo.Element for element operations.
10859  <pre><code>
10860  var els = Roo.select("#some-el div.some-class");
10861  // or select directly from an existing element
10862  var el = Roo.get('some-el');
10863  el.select('div.some-class');
10864
10865  els.setWidth(100); // all elements become 100 width
10866  els.hide(true); // all elements fade out and hide
10867  // or
10868  els.setWidth(100).hide(true);
10869  </code></pre><br><br>
10870  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10871  * actions will be performed on all the elements in this collection.</b>
10872  */
10873 Roo.CompositeElementLite = function(els){
10874     Roo.CompositeElementLite.superclass.constructor.call(this, els);
10875     this.el = new Roo.Element.Flyweight();
10876 };
10877 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10878     addElements : function(els){
10879         if(els){
10880             if(els instanceof Array){
10881                 this.elements = this.elements.concat(els);
10882             }else{
10883                 var yels = this.elements;
10884                 var index = yels.length-1;
10885                 for(var i = 0, len = els.length; i < len; i++) {
10886                     yels[++index] = els[i];
10887                 }
10888             }
10889         }
10890         return this;
10891     },
10892     invoke : function(fn, args){
10893         var els = this.elements;
10894         var el = this.el;
10895         for(var i = 0, len = els.length; i < len; i++) {
10896             el.dom = els[i];
10897                 Roo.Element.prototype[fn].apply(el, args);
10898         }
10899         return this;
10900     },
10901     /**
10902      * Returns a flyweight Element of the dom element object at the specified index
10903      * @param {Number} index
10904      * @return {Roo.Element}
10905      */
10906     item : function(index){
10907         if(!this.elements[index]){
10908             return null;
10909         }
10910         this.el.dom = this.elements[index];
10911         return this.el;
10912     },
10913
10914     // fixes scope with flyweight
10915     addListener : function(eventName, handler, scope, opt){
10916         var els = this.elements;
10917         for(var i = 0, len = els.length; i < len; i++) {
10918             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10919         }
10920         return this;
10921     },
10922
10923     /**
10924     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10925     * passed is the flyweight (shared) Roo.Element instance, so if you require a
10926     * a reference to the dom node, use el.dom.</b>
10927     * @param {Function} fn The function to call
10928     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10929     * @return {CompositeElement} this
10930     */
10931     each : function(fn, scope){
10932         var els = this.elements;
10933         var el = this.el;
10934         for(var i = 0, len = els.length; i < len; i++){
10935             el.dom = els[i];
10936                 if(fn.call(scope || el, el, this, i) === false){
10937                 break;
10938             }
10939         }
10940         return this;
10941     },
10942
10943     indexOf : function(el){
10944         return this.elements.indexOf(Roo.getDom(el));
10945     },
10946
10947     replaceElement : function(el, replacement, domReplace){
10948         var index = typeof el == 'number' ? el : this.indexOf(el);
10949         if(index !== -1){
10950             replacement = Roo.getDom(replacement);
10951             if(domReplace){
10952                 var d = this.elements[index];
10953                 d.parentNode.insertBefore(replacement, d);
10954                 d.parentNode.removeChild(d);
10955             }
10956             this.elements.splice(index, 1, replacement);
10957         }
10958         return this;
10959     }
10960 });
10961 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10962
10963 /*
10964  * Based on:
10965  * Ext JS Library 1.1.1
10966  * Copyright(c) 2006-2007, Ext JS, LLC.
10967  *
10968  * Originally Released Under LGPL - original licence link has changed is not relivant.
10969  *
10970  * Fork - LGPL
10971  * <script type="text/javascript">
10972  */
10973
10974  
10975
10976 /**
10977  * @class Roo.data.Connection
10978  * @extends Roo.util.Observable
10979  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10980  * either to a configured URL, or to a URL specified at request time.<br><br>
10981  * <p>
10982  * Requests made by this class are asynchronous, and will return immediately. No data from
10983  * the server will be available to the statement immediately following the {@link #request} call.
10984  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10985  * <p>
10986  * Note: If you are doing a file upload, you will not get a normal response object sent back to
10987  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10988  * The response object is created using the innerHTML of the IFRAME's document as the responseText
10989  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10990  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10991  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
10992  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10993  * standard DOM methods.
10994  * @constructor
10995  * @param {Object} config a configuration object.
10996  */
10997 Roo.data.Connection = function(config){
10998     Roo.apply(this, config);
10999     this.addEvents({
11000         /**
11001          * @event beforerequest
11002          * Fires before a network request is made to retrieve a data object.
11003          * @param {Connection} conn This Connection object.
11004          * @param {Object} options The options config object passed to the {@link #request} method.
11005          */
11006         "beforerequest" : true,
11007         /**
11008          * @event requestcomplete
11009          * Fires if the request was successfully completed.
11010          * @param {Connection} conn This Connection object.
11011          * @param {Object} response The XHR object containing the response data.
11012          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11013          * @param {Object} options The options config object passed to the {@link #request} method.
11014          */
11015         "requestcomplete" : true,
11016         /**
11017          * @event requestexception
11018          * Fires if an error HTTP status was returned from the server.
11019          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11020          * @param {Connection} conn This Connection object.
11021          * @param {Object} response The XHR object containing the response data.
11022          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11023          * @param {Object} options The options config object passed to the {@link #request} method.
11024          */
11025         "requestexception" : true
11026     });
11027     Roo.data.Connection.superclass.constructor.call(this);
11028 };
11029
11030 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11031     /**
11032      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11033      */
11034     /**
11035      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11036      * extra parameters to each request made by this object. (defaults to undefined)
11037      */
11038     /**
11039      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11040      *  to each request made by this object. (defaults to undefined)
11041      */
11042     /**
11043      * @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)
11044      */
11045     /**
11046      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11047      */
11048     timeout : 30000,
11049     /**
11050      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11051      * @type Boolean
11052      */
11053     autoAbort:false,
11054
11055     /**
11056      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11057      * @type Boolean
11058      */
11059     disableCaching: true,
11060
11061     /**
11062      * Sends an HTTP request to a remote server.
11063      * @param {Object} options An object which may contain the following properties:<ul>
11064      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11065      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11066      * request, a url encoded string or a function to call to get either.</li>
11067      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11068      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11069      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11070      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11071      * <li>options {Object} The parameter to the request call.</li>
11072      * <li>success {Boolean} True if the request succeeded.</li>
11073      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11074      * </ul></li>
11075      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11076      * The callback is passed the following parameters:<ul>
11077      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11078      * <li>options {Object} The parameter to the request call.</li>
11079      * </ul></li>
11080      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11081      * The callback is passed the following parameters:<ul>
11082      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11083      * <li>options {Object} The parameter to the request call.</li>
11084      * </ul></li>
11085      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11086      * for the callback function. Defaults to the browser window.</li>
11087      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11088      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11089      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11090      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11091      * params for the post data. Any params will be appended to the URL.</li>
11092      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11093      * </ul>
11094      * @return {Number} transactionId
11095      */
11096     request : function(o){
11097         if(this.fireEvent("beforerequest", this, o) !== false){
11098             var p = o.params;
11099
11100             if(typeof p == "function"){
11101                 p = p.call(o.scope||window, o);
11102             }
11103             if(typeof p == "object"){
11104                 p = Roo.urlEncode(o.params);
11105             }
11106             if(this.extraParams){
11107                 var extras = Roo.urlEncode(this.extraParams);
11108                 p = p ? (p + '&' + extras) : extras;
11109             }
11110
11111             var url = o.url || this.url;
11112             if(typeof url == 'function'){
11113                 url = url.call(o.scope||window, o);
11114             }
11115
11116             if(o.form){
11117                 var form = Roo.getDom(o.form);
11118                 url = url || form.action;
11119
11120                 var enctype = form.getAttribute("enctype");
11121                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11122                     return this.doFormUpload(o, p, url);
11123                 }
11124                 var f = Roo.lib.Ajax.serializeForm(form);
11125                 p = p ? (p + '&' + f) : f;
11126             }
11127
11128             var hs = o.headers;
11129             if(this.defaultHeaders){
11130                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11131                 if(!o.headers){
11132                     o.headers = hs;
11133                 }
11134             }
11135
11136             var cb = {
11137                 success: this.handleResponse,
11138                 failure: this.handleFailure,
11139                 scope: this,
11140                 argument: {options: o},
11141                 timeout : this.timeout
11142             };
11143
11144             var method = o.method||this.method||(p ? "POST" : "GET");
11145
11146             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11147                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11148             }
11149
11150             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11151                 if(o.autoAbort){
11152                     this.abort();
11153                 }
11154             }else if(this.autoAbort !== false){
11155                 this.abort();
11156             }
11157
11158             if((method == 'GET' && p) || o.xmlData){
11159                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11160                 p = '';
11161             }
11162             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11163             return this.transId;
11164         }else{
11165             Roo.callback(o.callback, o.scope, [o, null, null]);
11166             return null;
11167         }
11168     },
11169
11170     /**
11171      * Determine whether this object has a request outstanding.
11172      * @param {Number} transactionId (Optional) defaults to the last transaction
11173      * @return {Boolean} True if there is an outstanding request.
11174      */
11175     isLoading : function(transId){
11176         if(transId){
11177             return Roo.lib.Ajax.isCallInProgress(transId);
11178         }else{
11179             return this.transId ? true : false;
11180         }
11181     },
11182
11183     /**
11184      * Aborts any outstanding request.
11185      * @param {Number} transactionId (Optional) defaults to the last transaction
11186      */
11187     abort : function(transId){
11188         if(transId || this.isLoading()){
11189             Roo.lib.Ajax.abort(transId || this.transId);
11190         }
11191     },
11192
11193     // private
11194     handleResponse : function(response){
11195         this.transId = false;
11196         var options = response.argument.options;
11197         response.argument = options ? options.argument : null;
11198         this.fireEvent("requestcomplete", this, response, options);
11199         Roo.callback(options.success, options.scope, [response, options]);
11200         Roo.callback(options.callback, options.scope, [options, true, response]);
11201     },
11202
11203     // private
11204     handleFailure : function(response, e){
11205         this.transId = false;
11206         var options = response.argument.options;
11207         response.argument = options ? options.argument : null;
11208         this.fireEvent("requestexception", this, response, options, e);
11209         Roo.callback(options.failure, options.scope, [response, options]);
11210         Roo.callback(options.callback, options.scope, [options, false, response]);
11211     },
11212
11213     // private
11214     doFormUpload : function(o, ps, url){
11215         var id = Roo.id();
11216         var frame = document.createElement('iframe');
11217         frame.id = id;
11218         frame.name = id;
11219         frame.className = 'x-hidden';
11220         if(Roo.isIE){
11221             frame.src = Roo.SSL_SECURE_URL;
11222         }
11223         document.body.appendChild(frame);
11224
11225         if(Roo.isIE){
11226            document.frames[id].name = id;
11227         }
11228
11229         var form = Roo.getDom(o.form);
11230         form.target = id;
11231         form.method = 'POST';
11232         form.enctype = form.encoding = 'multipart/form-data';
11233         if(url){
11234             form.action = url;
11235         }
11236
11237         var hiddens, hd;
11238         if(ps){ // add dynamic params
11239             hiddens = [];
11240             ps = Roo.urlDecode(ps, false);
11241             for(var k in ps){
11242                 if(ps.hasOwnProperty(k)){
11243                     hd = document.createElement('input');
11244                     hd.type = 'hidden';
11245                     hd.name = k;
11246                     hd.value = ps[k];
11247                     form.appendChild(hd);
11248                     hiddens.push(hd);
11249                 }
11250             }
11251         }
11252
11253         function cb(){
11254             var r = {  // bogus response object
11255                 responseText : '',
11256                 responseXML : null
11257             };
11258
11259             r.argument = o ? o.argument : null;
11260
11261             try { //
11262                 var doc;
11263                 if(Roo.isIE){
11264                     doc = frame.contentWindow.document;
11265                 }else {
11266                     doc = (frame.contentDocument || window.frames[id].document);
11267                 }
11268                 if(doc && doc.body){
11269                     r.responseText = doc.body.innerHTML;
11270                 }
11271                 if(doc && doc.XMLDocument){
11272                     r.responseXML = doc.XMLDocument;
11273                 }else {
11274                     r.responseXML = doc;
11275                 }
11276             }
11277             catch(e) {
11278                 // ignore
11279             }
11280
11281             Roo.EventManager.removeListener(frame, 'load', cb, this);
11282
11283             this.fireEvent("requestcomplete", this, r, o);
11284             Roo.callback(o.success, o.scope, [r, o]);
11285             Roo.callback(o.callback, o.scope, [o, true, r]);
11286
11287             setTimeout(function(){document.body.removeChild(frame);}, 100);
11288         }
11289
11290         Roo.EventManager.on(frame, 'load', cb, this);
11291         form.submit();
11292
11293         if(hiddens){ // remove dynamic params
11294             for(var i = 0, len = hiddens.length; i < len; i++){
11295                 form.removeChild(hiddens[i]);
11296             }
11297         }
11298     }
11299 });
11300
11301 /**
11302  * @class Roo.Ajax
11303  * @extends Roo.data.Connection
11304  * Global Ajax request class.
11305  *
11306  * @singleton
11307  */
11308 Roo.Ajax = new Roo.data.Connection({
11309     // fix up the docs
11310    /**
11311      * @cfg {String} url @hide
11312      */
11313     /**
11314      * @cfg {Object} extraParams @hide
11315      */
11316     /**
11317      * @cfg {Object} defaultHeaders @hide
11318      */
11319     /**
11320      * @cfg {String} method (Optional) @hide
11321      */
11322     /**
11323      * @cfg {Number} timeout (Optional) @hide
11324      */
11325     /**
11326      * @cfg {Boolean} autoAbort (Optional) @hide
11327      */
11328
11329     /**
11330      * @cfg {Boolean} disableCaching (Optional) @hide
11331      */
11332
11333     /**
11334      * @property  disableCaching
11335      * True to add a unique cache-buster param to GET requests. (defaults to true)
11336      * @type Boolean
11337      */
11338     /**
11339      * @property  url
11340      * The default URL to be used for requests to the server. (defaults to undefined)
11341      * @type String
11342      */
11343     /**
11344      * @property  extraParams
11345      * An object containing properties which are used as
11346      * extra parameters to each request made by this object. (defaults to undefined)
11347      * @type Object
11348      */
11349     /**
11350      * @property  defaultHeaders
11351      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11352      * @type Object
11353      */
11354     /**
11355      * @property  method
11356      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11357      * @type String
11358      */
11359     /**
11360      * @property  timeout
11361      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11362      * @type Number
11363      */
11364
11365     /**
11366      * @property  autoAbort
11367      * Whether a new request should abort any pending requests. (defaults to false)
11368      * @type Boolean
11369      */
11370     autoAbort : false,
11371
11372     /**
11373      * Serialize the passed form into a url encoded string
11374      * @param {String/HTMLElement} form
11375      * @return {String}
11376      */
11377     serializeForm : function(form){
11378         return Roo.lib.Ajax.serializeForm(form);
11379     }
11380 });/*
11381  * Based on:
11382  * Ext JS Library 1.1.1
11383  * Copyright(c) 2006-2007, Ext JS, LLC.
11384  *
11385  * Originally Released Under LGPL - original licence link has changed is not relivant.
11386  *
11387  * Fork - LGPL
11388  * <script type="text/javascript">
11389  */
11390  
11391 /**
11392  * @class Roo.Ajax
11393  * @extends Roo.data.Connection
11394  * Global Ajax request class.
11395  *
11396  * @instanceOf  Roo.data.Connection
11397  */
11398 Roo.Ajax = new Roo.data.Connection({
11399     // fix up the docs
11400     
11401     /**
11402      * fix up scoping
11403      * @scope Roo.Ajax
11404      */
11405     
11406    /**
11407      * @cfg {String} url @hide
11408      */
11409     /**
11410      * @cfg {Object} extraParams @hide
11411      */
11412     /**
11413      * @cfg {Object} defaultHeaders @hide
11414      */
11415     /**
11416      * @cfg {String} method (Optional) @hide
11417      */
11418     /**
11419      * @cfg {Number} timeout (Optional) @hide
11420      */
11421     /**
11422      * @cfg {Boolean} autoAbort (Optional) @hide
11423      */
11424
11425     /**
11426      * @cfg {Boolean} disableCaching (Optional) @hide
11427      */
11428
11429     /**
11430      * @property  disableCaching
11431      * True to add a unique cache-buster param to GET requests. (defaults to true)
11432      * @type Boolean
11433      */
11434     /**
11435      * @property  url
11436      * The default URL to be used for requests to the server. (defaults to undefined)
11437      * @type String
11438      */
11439     /**
11440      * @property  extraParams
11441      * An object containing properties which are used as
11442      * extra parameters to each request made by this object. (defaults to undefined)
11443      * @type Object
11444      */
11445     /**
11446      * @property  defaultHeaders
11447      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11448      * @type Object
11449      */
11450     /**
11451      * @property  method
11452      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11453      * @type String
11454      */
11455     /**
11456      * @property  timeout
11457      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11458      * @type Number
11459      */
11460
11461     /**
11462      * @property  autoAbort
11463      * Whether a new request should abort any pending requests. (defaults to false)
11464      * @type Boolean
11465      */
11466     autoAbort : false,
11467
11468     /**
11469      * Serialize the passed form into a url encoded string
11470      * @param {String/HTMLElement} form
11471      * @return {String}
11472      */
11473     serializeForm : function(form){
11474         return Roo.lib.Ajax.serializeForm(form);
11475     }
11476 });/*
11477  * Based on:
11478  * Ext JS Library 1.1.1
11479  * Copyright(c) 2006-2007, Ext JS, LLC.
11480  *
11481  * Originally Released Under LGPL - original licence link has changed is not relivant.
11482  *
11483  * Fork - LGPL
11484  * <script type="text/javascript">
11485  */
11486
11487  
11488 /**
11489  * @class Roo.UpdateManager
11490  * @extends Roo.util.Observable
11491  * Provides AJAX-style update for Element object.<br><br>
11492  * Usage:<br>
11493  * <pre><code>
11494  * // Get it from a Roo.Element object
11495  * var el = Roo.get("foo");
11496  * var mgr = el.getUpdateManager();
11497  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11498  * ...
11499  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11500  * <br>
11501  * // or directly (returns the same UpdateManager instance)
11502  * var mgr = new Roo.UpdateManager("myElementId");
11503  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11504  * mgr.on("update", myFcnNeedsToKnow);
11505  * <br>
11506    // short handed call directly from the element object
11507    Roo.get("foo").load({
11508         url: "bar.php",
11509         scripts:true,
11510         params: "for=bar",
11511         text: "Loading Foo..."
11512    });
11513  * </code></pre>
11514  * @constructor
11515  * Create new UpdateManager directly.
11516  * @param {String/HTMLElement/Roo.Element} el The element to update
11517  * @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).
11518  */
11519 Roo.UpdateManager = function(el, forceNew){
11520     el = Roo.get(el);
11521     if(!forceNew && el.updateManager){
11522         return el.updateManager;
11523     }
11524     /**
11525      * The Element object
11526      * @type Roo.Element
11527      */
11528     this.el = el;
11529     /**
11530      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11531      * @type String
11532      */
11533     this.defaultUrl = null;
11534
11535     this.addEvents({
11536         /**
11537          * @event beforeupdate
11538          * Fired before an update is made, return false from your handler and the update is cancelled.
11539          * @param {Roo.Element} el
11540          * @param {String/Object/Function} url
11541          * @param {String/Object} params
11542          */
11543         "beforeupdate": true,
11544         /**
11545          * @event update
11546          * Fired after successful update is made.
11547          * @param {Roo.Element} el
11548          * @param {Object} oResponseObject The response Object
11549          */
11550         "update": true,
11551         /**
11552          * @event failure
11553          * Fired on update failure.
11554          * @param {Roo.Element} el
11555          * @param {Object} oResponseObject The response Object
11556          */
11557         "failure": true
11558     });
11559     var d = Roo.UpdateManager.defaults;
11560     /**
11561      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11562      * @type String
11563      */
11564     this.sslBlankUrl = d.sslBlankUrl;
11565     /**
11566      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11567      * @type Boolean
11568      */
11569     this.disableCaching = d.disableCaching;
11570     /**
11571      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11572      * @type String
11573      */
11574     this.indicatorText = d.indicatorText;
11575     /**
11576      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11577      * @type String
11578      */
11579     this.showLoadIndicator = d.showLoadIndicator;
11580     /**
11581      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11582      * @type Number
11583      */
11584     this.timeout = d.timeout;
11585
11586     /**
11587      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11588      * @type Boolean
11589      */
11590     this.loadScripts = d.loadScripts;
11591
11592     /**
11593      * Transaction object of current executing transaction
11594      */
11595     this.transaction = null;
11596
11597     /**
11598      * @private
11599      */
11600     this.autoRefreshProcId = null;
11601     /**
11602      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11603      * @type Function
11604      */
11605     this.refreshDelegate = this.refresh.createDelegate(this);
11606     /**
11607      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11608      * @type Function
11609      */
11610     this.updateDelegate = this.update.createDelegate(this);
11611     /**
11612      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11613      * @type Function
11614      */
11615     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11616     /**
11617      * @private
11618      */
11619     this.successDelegate = this.processSuccess.createDelegate(this);
11620     /**
11621      * @private
11622      */
11623     this.failureDelegate = this.processFailure.createDelegate(this);
11624
11625     if(!this.renderer){
11626      /**
11627       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11628       */
11629     this.renderer = new Roo.UpdateManager.BasicRenderer();
11630     }
11631     
11632     Roo.UpdateManager.superclass.constructor.call(this);
11633 };
11634
11635 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11636     /**
11637      * Get the Element this UpdateManager is bound to
11638      * @return {Roo.Element} The element
11639      */
11640     getEl : function(){
11641         return this.el;
11642     },
11643     /**
11644      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11645      * @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:
11646 <pre><code>
11647 um.update({<br/>
11648     url: "your-url.php",<br/>
11649     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11650     callback: yourFunction,<br/>
11651     scope: yourObject, //(optional scope)  <br/>
11652     discardUrl: false, <br/>
11653     nocache: false,<br/>
11654     text: "Loading...",<br/>
11655     timeout: 30,<br/>
11656     scripts: false<br/>
11657 });
11658 </code></pre>
11659      * The only required property is url. The optional properties nocache, text and scripts
11660      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11661      * @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}
11662      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11663      * @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.
11664      */
11665     update : function(url, params, callback, discardUrl){
11666         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11667             var method = this.method, cfg;
11668             if(typeof url == "object"){ // must be config object
11669                 cfg = url;
11670                 url = cfg.url;
11671                 params = params || cfg.params;
11672                 callback = callback || cfg.callback;
11673                 discardUrl = discardUrl || cfg.discardUrl;
11674                 if(callback && cfg.scope){
11675                     callback = callback.createDelegate(cfg.scope);
11676                 }
11677                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11678                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11679                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11680                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11681                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11682             }
11683             this.showLoading();
11684             if(!discardUrl){
11685                 this.defaultUrl = url;
11686             }
11687             if(typeof url == "function"){
11688                 url = url.call(this);
11689             }
11690
11691             method = method || (params ? "POST" : "GET");
11692             if(method == "GET"){
11693                 url = this.prepareUrl(url);
11694             }
11695
11696             var o = Roo.apply(cfg ||{}, {
11697                 url : url,
11698                 params: params,
11699                 success: this.successDelegate,
11700                 failure: this.failureDelegate,
11701                 callback: undefined,
11702                 timeout: (this.timeout*1000),
11703                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11704             });
11705
11706             this.transaction = Roo.Ajax.request(o);
11707         }
11708     },
11709
11710     /**
11711      * 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.
11712      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11713      * @param {String/HTMLElement} form The form Id or form element
11714      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11715      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11716      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11717      */
11718     formUpdate : function(form, url, reset, callback){
11719         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11720             if(typeof url == "function"){
11721                 url = url.call(this);
11722             }
11723             form = Roo.getDom(form);
11724             this.transaction = Roo.Ajax.request({
11725                 form: form,
11726                 url:url,
11727                 success: this.successDelegate,
11728                 failure: this.failureDelegate,
11729                 timeout: (this.timeout*1000),
11730                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11731             });
11732             this.showLoading.defer(1, this);
11733         }
11734     },
11735
11736     /**
11737      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11738      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11739      */
11740     refresh : function(callback){
11741         if(this.defaultUrl == null){
11742             return;
11743         }
11744         this.update(this.defaultUrl, null, callback, true);
11745     },
11746
11747     /**
11748      * Set this element to auto refresh.
11749      * @param {Number} interval How often to update (in seconds).
11750      * @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)
11751      * @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}
11752      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11753      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11754      */
11755     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11756         if(refreshNow){
11757             this.update(url || this.defaultUrl, params, callback, true);
11758         }
11759         if(this.autoRefreshProcId){
11760             clearInterval(this.autoRefreshProcId);
11761         }
11762         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11763     },
11764
11765     /**
11766      * Stop auto refresh on this element.
11767      */
11768      stopAutoRefresh : function(){
11769         if(this.autoRefreshProcId){
11770             clearInterval(this.autoRefreshProcId);
11771             delete this.autoRefreshProcId;
11772         }
11773     },
11774
11775     isAutoRefreshing : function(){
11776        return this.autoRefreshProcId ? true : false;
11777     },
11778     /**
11779      * Called to update the element to "Loading" state. Override to perform custom action.
11780      */
11781     showLoading : function(){
11782         if(this.showLoadIndicator){
11783             this.el.update(this.indicatorText);
11784         }
11785     },
11786
11787     /**
11788      * Adds unique parameter to query string if disableCaching = true
11789      * @private
11790      */
11791     prepareUrl : function(url){
11792         if(this.disableCaching){
11793             var append = "_dc=" + (new Date().getTime());
11794             if(url.indexOf("?") !== -1){
11795                 url += "&" + append;
11796             }else{
11797                 url += "?" + append;
11798             }
11799         }
11800         return url;
11801     },
11802
11803     /**
11804      * @private
11805      */
11806     processSuccess : function(response){
11807         this.transaction = null;
11808         if(response.argument.form && response.argument.reset){
11809             try{ // put in try/catch since some older FF releases had problems with this
11810                 response.argument.form.reset();
11811             }catch(e){}
11812         }
11813         if(this.loadScripts){
11814             this.renderer.render(this.el, response, this,
11815                 this.updateComplete.createDelegate(this, [response]));
11816         }else{
11817             this.renderer.render(this.el, response, this);
11818             this.updateComplete(response);
11819         }
11820     },
11821
11822     updateComplete : function(response){
11823         this.fireEvent("update", this.el, response);
11824         if(typeof response.argument.callback == "function"){
11825             response.argument.callback(this.el, true, response);
11826         }
11827     },
11828
11829     /**
11830      * @private
11831      */
11832     processFailure : function(response){
11833         this.transaction = null;
11834         this.fireEvent("failure", this.el, response);
11835         if(typeof response.argument.callback == "function"){
11836             response.argument.callback(this.el, false, response);
11837         }
11838     },
11839
11840     /**
11841      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11842      * @param {Object} renderer The object implementing the render() method
11843      */
11844     setRenderer : function(renderer){
11845         this.renderer = renderer;
11846     },
11847
11848     getRenderer : function(){
11849        return this.renderer;
11850     },
11851
11852     /**
11853      * Set the defaultUrl used for updates
11854      * @param {String/Function} defaultUrl The url or a function to call to get the url
11855      */
11856     setDefaultUrl : function(defaultUrl){
11857         this.defaultUrl = defaultUrl;
11858     },
11859
11860     /**
11861      * Aborts the executing transaction
11862      */
11863     abort : function(){
11864         if(this.transaction){
11865             Roo.Ajax.abort(this.transaction);
11866         }
11867     },
11868
11869     /**
11870      * Returns true if an update is in progress
11871      * @return {Boolean}
11872      */
11873     isUpdating : function(){
11874         if(this.transaction){
11875             return Roo.Ajax.isLoading(this.transaction);
11876         }
11877         return false;
11878     }
11879 });
11880
11881 /**
11882  * @class Roo.UpdateManager.defaults
11883  * @static (not really - but it helps the doc tool)
11884  * The defaults collection enables customizing the default properties of UpdateManager
11885  */
11886    Roo.UpdateManager.defaults = {
11887        /**
11888          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11889          * @type Number
11890          */
11891          timeout : 30,
11892
11893          /**
11894          * True to process scripts by default (Defaults to false).
11895          * @type Boolean
11896          */
11897         loadScripts : false,
11898
11899         /**
11900         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11901         * @type String
11902         */
11903         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11904         /**
11905          * Whether to append unique parameter on get request to disable caching (Defaults to false).
11906          * @type Boolean
11907          */
11908         disableCaching : false,
11909         /**
11910          * Whether to show indicatorText when loading (Defaults to true).
11911          * @type Boolean
11912          */
11913         showLoadIndicator : true,
11914         /**
11915          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11916          * @type String
11917          */
11918         indicatorText : '<div class="loading-indicator">Loading...</div>'
11919    };
11920
11921 /**
11922  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11923  *Usage:
11924  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11925  * @param {String/HTMLElement/Roo.Element} el The element to update
11926  * @param {String} url The url
11927  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11928  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11929  * @static
11930  * @deprecated
11931  * @member Roo.UpdateManager
11932  */
11933 Roo.UpdateManager.updateElement = function(el, url, params, options){
11934     var um = Roo.get(el, true).getUpdateManager();
11935     Roo.apply(um, options);
11936     um.update(url, params, options ? options.callback : null);
11937 };
11938 // alias for backwards compat
11939 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11940 /**
11941  * @class Roo.UpdateManager.BasicRenderer
11942  * Default Content renderer. Updates the elements innerHTML with the responseText.
11943  */
11944 Roo.UpdateManager.BasicRenderer = function(){};
11945
11946 Roo.UpdateManager.BasicRenderer.prototype = {
11947     /**
11948      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11949      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11950      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11951      * @param {Roo.Element} el The element being rendered
11952      * @param {Object} response The YUI Connect response object
11953      * @param {UpdateManager} updateManager The calling update manager
11954      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11955      */
11956      render : function(el, response, updateManager, callback){
11957         el.update(response.responseText, updateManager.loadScripts, callback);
11958     }
11959 };
11960 /*
11961  * Based on:
11962  * Ext JS Library 1.1.1
11963  * Copyright(c) 2006-2007, Ext JS, LLC.
11964  *
11965  * Originally Released Under LGPL - original licence link has changed is not relivant.
11966  *
11967  * Fork - LGPL
11968  * <script type="text/javascript">
11969  */
11970
11971 /**
11972  * @class Roo.util.DelayedTask
11973  * Provides a convenient method of performing setTimeout where a new
11974  * timeout cancels the old timeout. An example would be performing validation on a keypress.
11975  * You can use this class to buffer
11976  * the keypress events for a certain number of milliseconds, and perform only if they stop
11977  * for that amount of time.
11978  * @constructor The parameters to this constructor serve as defaults and are not required.
11979  * @param {Function} fn (optional) The default function to timeout
11980  * @param {Object} scope (optional) The default scope of that timeout
11981  * @param {Array} args (optional) The default Array of arguments
11982  */
11983 Roo.util.DelayedTask = function(fn, scope, args){
11984     var id = null, d, t;
11985
11986     var call = function(){
11987         var now = new Date().getTime();
11988         if(now - t >= d){
11989             clearInterval(id);
11990             id = null;
11991             fn.apply(scope, args || []);
11992         }
11993     };
11994     /**
11995      * Cancels any pending timeout and queues a new one
11996      * @param {Number} delay The milliseconds to delay
11997      * @param {Function} newFn (optional) Overrides function passed to constructor
11998      * @param {Object} newScope (optional) Overrides scope passed to constructor
11999      * @param {Array} newArgs (optional) Overrides args passed to constructor
12000      */
12001     this.delay = function(delay, newFn, newScope, newArgs){
12002         if(id && delay != d){
12003             this.cancel();
12004         }
12005         d = delay;
12006         t = new Date().getTime();
12007         fn = newFn || fn;
12008         scope = newScope || scope;
12009         args = newArgs || args;
12010         if(!id){
12011             id = setInterval(call, d);
12012         }
12013     };
12014
12015     /**
12016      * Cancel the last queued timeout
12017      */
12018     this.cancel = function(){
12019         if(id){
12020             clearInterval(id);
12021             id = null;
12022         }
12023     };
12024 };/*
12025  * Based on:
12026  * Ext JS Library 1.1.1
12027  * Copyright(c) 2006-2007, Ext JS, LLC.
12028  *
12029  * Originally Released Under LGPL - original licence link has changed is not relivant.
12030  *
12031  * Fork - LGPL
12032  * <script type="text/javascript">
12033  */
12034  
12035  
12036 Roo.util.TaskRunner = function(interval){
12037     interval = interval || 10;
12038     var tasks = [], removeQueue = [];
12039     var id = 0;
12040     var running = false;
12041
12042     var stopThread = function(){
12043         running = false;
12044         clearInterval(id);
12045         id = 0;
12046     };
12047
12048     var startThread = function(){
12049         if(!running){
12050             running = true;
12051             id = setInterval(runTasks, interval);
12052         }
12053     };
12054
12055     var removeTask = function(task){
12056         removeQueue.push(task);
12057         if(task.onStop){
12058             task.onStop();
12059         }
12060     };
12061
12062     var runTasks = function(){
12063         if(removeQueue.length > 0){
12064             for(var i = 0, len = removeQueue.length; i < len; i++){
12065                 tasks.remove(removeQueue[i]);
12066             }
12067             removeQueue = [];
12068             if(tasks.length < 1){
12069                 stopThread();
12070                 return;
12071             }
12072         }
12073         var now = new Date().getTime();
12074         for(var i = 0, len = tasks.length; i < len; ++i){
12075             var t = tasks[i];
12076             var itime = now - t.taskRunTime;
12077             if(t.interval <= itime){
12078                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12079                 t.taskRunTime = now;
12080                 if(rt === false || t.taskRunCount === t.repeat){
12081                     removeTask(t);
12082                     return;
12083                 }
12084             }
12085             if(t.duration && t.duration <= (now - t.taskStartTime)){
12086                 removeTask(t);
12087             }
12088         }
12089     };
12090
12091     /**
12092      * Queues a new task.
12093      * @param {Object} task
12094      */
12095     this.start = function(task){
12096         tasks.push(task);
12097         task.taskStartTime = new Date().getTime();
12098         task.taskRunTime = 0;
12099         task.taskRunCount = 0;
12100         startThread();
12101         return task;
12102     };
12103
12104     this.stop = function(task){
12105         removeTask(task);
12106         return task;
12107     };
12108
12109     this.stopAll = function(){
12110         stopThread();
12111         for(var i = 0, len = tasks.length; i < len; i++){
12112             if(tasks[i].onStop){
12113                 tasks[i].onStop();
12114             }
12115         }
12116         tasks = [];
12117         removeQueue = [];
12118     };
12119 };
12120
12121 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12122  * Based on:
12123  * Ext JS Library 1.1.1
12124  * Copyright(c) 2006-2007, Ext JS, LLC.
12125  *
12126  * Originally Released Under LGPL - original licence link has changed is not relivant.
12127  *
12128  * Fork - LGPL
12129  * <script type="text/javascript">
12130  */
12131
12132  
12133 /**
12134  * @class Roo.util.MixedCollection
12135  * @extends Roo.util.Observable
12136  * A Collection class that maintains both numeric indexes and keys and exposes events.
12137  * @constructor
12138  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12139  * collection (defaults to false)
12140  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12141  * and return the key value for that item.  This is used when available to look up the key on items that
12142  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12143  * equivalent to providing an implementation for the {@link #getKey} method.
12144  */
12145 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12146     this.items = [];
12147     this.map = {};
12148     this.keys = [];
12149     this.length = 0;
12150     this.addEvents({
12151         /**
12152          * @event clear
12153          * Fires when the collection is cleared.
12154          */
12155         "clear" : true,
12156         /**
12157          * @event add
12158          * Fires when an item is added to the collection.
12159          * @param {Number} index The index at which the item was added.
12160          * @param {Object} o The item added.
12161          * @param {String} key The key associated with the added item.
12162          */
12163         "add" : true,
12164         /**
12165          * @event replace
12166          * Fires when an item is replaced in the collection.
12167          * @param {String} key he key associated with the new added.
12168          * @param {Object} old The item being replaced.
12169          * @param {Object} new The new item.
12170          */
12171         "replace" : true,
12172         /**
12173          * @event remove
12174          * Fires when an item is removed from the collection.
12175          * @param {Object} o The item being removed.
12176          * @param {String} key (optional) The key associated with the removed item.
12177          */
12178         "remove" : true,
12179         "sort" : true
12180     });
12181     this.allowFunctions = allowFunctions === true;
12182     if(keyFn){
12183         this.getKey = keyFn;
12184     }
12185     Roo.util.MixedCollection.superclass.constructor.call(this);
12186 };
12187
12188 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12189     allowFunctions : false,
12190     
12191 /**
12192  * Adds an item to the collection.
12193  * @param {String} key The key to associate with the item
12194  * @param {Object} o The item to add.
12195  * @return {Object} The item added.
12196  */
12197     add : function(key, o){
12198         if(arguments.length == 1){
12199             o = arguments[0];
12200             key = this.getKey(o);
12201         }
12202         if(typeof key == "undefined" || key === null){
12203             this.length++;
12204             this.items.push(o);
12205             this.keys.push(null);
12206         }else{
12207             var old = this.map[key];
12208             if(old){
12209                 return this.replace(key, o);
12210             }
12211             this.length++;
12212             this.items.push(o);
12213             this.map[key] = o;
12214             this.keys.push(key);
12215         }
12216         this.fireEvent("add", this.length-1, o, key);
12217         return o;
12218     },
12219    
12220 /**
12221   * MixedCollection has a generic way to fetch keys if you implement getKey.
12222 <pre><code>
12223 // normal way
12224 var mc = new Roo.util.MixedCollection();
12225 mc.add(someEl.dom.id, someEl);
12226 mc.add(otherEl.dom.id, otherEl);
12227 //and so on
12228
12229 // using getKey
12230 var mc = new Roo.util.MixedCollection();
12231 mc.getKey = function(el){
12232    return el.dom.id;
12233 };
12234 mc.add(someEl);
12235 mc.add(otherEl);
12236
12237 // or via the constructor
12238 var mc = new Roo.util.MixedCollection(false, function(el){
12239    return el.dom.id;
12240 });
12241 mc.add(someEl);
12242 mc.add(otherEl);
12243 </code></pre>
12244  * @param o {Object} The item for which to find the key.
12245  * @return {Object} The key for the passed item.
12246  */
12247     getKey : function(o){
12248          return o.id; 
12249     },
12250    
12251 /**
12252  * Replaces an item in the collection.
12253  * @param {String} key The key associated with the item to replace, or the item to replace.
12254  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12255  * @return {Object}  The new item.
12256  */
12257     replace : function(key, o){
12258         if(arguments.length == 1){
12259             o = arguments[0];
12260             key = this.getKey(o);
12261         }
12262         var old = this.item(key);
12263         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12264              return this.add(key, o);
12265         }
12266         var index = this.indexOfKey(key);
12267         this.items[index] = o;
12268         this.map[key] = o;
12269         this.fireEvent("replace", key, old, o);
12270         return o;
12271     },
12272    
12273 /**
12274  * Adds all elements of an Array or an Object to the collection.
12275  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12276  * an Array of values, each of which are added to the collection.
12277  */
12278     addAll : function(objs){
12279         if(arguments.length > 1 || objs instanceof Array){
12280             var args = arguments.length > 1 ? arguments : objs;
12281             for(var i = 0, len = args.length; i < len; i++){
12282                 this.add(args[i]);
12283             }
12284         }else{
12285             for(var key in objs){
12286                 if(this.allowFunctions || typeof objs[key] != "function"){
12287                     this.add(key, objs[key]);
12288                 }
12289             }
12290         }
12291     },
12292    
12293 /**
12294  * Executes the specified function once for every item in the collection, passing each
12295  * item as the first and only parameter. returning false from the function will stop the iteration.
12296  * @param {Function} fn The function to execute for each item.
12297  * @param {Object} scope (optional) The scope in which to execute the function.
12298  */
12299     each : function(fn, scope){
12300         var items = [].concat(this.items); // each safe for removal
12301         for(var i = 0, len = items.length; i < len; i++){
12302             if(fn.call(scope || items[i], items[i], i, len) === false){
12303                 break;
12304             }
12305         }
12306     },
12307    
12308 /**
12309  * Executes the specified function once for every key in the collection, passing each
12310  * key, and its associated item as the first two parameters.
12311  * @param {Function} fn The function to execute for each item.
12312  * @param {Object} scope (optional) The scope in which to execute the function.
12313  */
12314     eachKey : function(fn, scope){
12315         for(var i = 0, len = this.keys.length; i < len; i++){
12316             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12317         }
12318     },
12319    
12320 /**
12321  * Returns the first item in the collection which elicits a true return value from the
12322  * passed selection function.
12323  * @param {Function} fn The selection function to execute for each item.
12324  * @param {Object} scope (optional) The scope in which to execute the function.
12325  * @return {Object} The first item in the collection which returned true from the selection function.
12326  */
12327     find : function(fn, scope){
12328         for(var i = 0, len = this.items.length; i < len; i++){
12329             if(fn.call(scope || window, this.items[i], this.keys[i])){
12330                 return this.items[i];
12331             }
12332         }
12333         return null;
12334     },
12335    
12336 /**
12337  * Inserts an item at the specified index in the collection.
12338  * @param {Number} index The index to insert the item at.
12339  * @param {String} key The key to associate with the new item, or the item itself.
12340  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12341  * @return {Object} The item inserted.
12342  */
12343     insert : function(index, key, o){
12344         if(arguments.length == 2){
12345             o = arguments[1];
12346             key = this.getKey(o);
12347         }
12348         if(index >= this.length){
12349             return this.add(key, o);
12350         }
12351         this.length++;
12352         this.items.splice(index, 0, o);
12353         if(typeof key != "undefined" && key != null){
12354             this.map[key] = o;
12355         }
12356         this.keys.splice(index, 0, key);
12357         this.fireEvent("add", index, o, key);
12358         return o;
12359     },
12360    
12361 /**
12362  * Removed an item from the collection.
12363  * @param {Object} o The item to remove.
12364  * @return {Object} The item removed.
12365  */
12366     remove : function(o){
12367         return this.removeAt(this.indexOf(o));
12368     },
12369    
12370 /**
12371  * Remove an item from a specified index in the collection.
12372  * @param {Number} index The index within the collection of the item to remove.
12373  */
12374     removeAt : function(index){
12375         if(index < this.length && index >= 0){
12376             this.length--;
12377             var o = this.items[index];
12378             this.items.splice(index, 1);
12379             var key = this.keys[index];
12380             if(typeof key != "undefined"){
12381                 delete this.map[key];
12382             }
12383             this.keys.splice(index, 1);
12384             this.fireEvent("remove", o, key);
12385         }
12386     },
12387    
12388 /**
12389  * Removed an item associated with the passed key fom the collection.
12390  * @param {String} key The key of the item to remove.
12391  */
12392     removeKey : function(key){
12393         return this.removeAt(this.indexOfKey(key));
12394     },
12395    
12396 /**
12397  * Returns the number of items in the collection.
12398  * @return {Number} the number of items in the collection.
12399  */
12400     getCount : function(){
12401         return this.length; 
12402     },
12403    
12404 /**
12405  * Returns index within the collection of the passed Object.
12406  * @param {Object} o The item to find the index of.
12407  * @return {Number} index of the item.
12408  */
12409     indexOf : function(o){
12410         if(!this.items.indexOf){
12411             for(var i = 0, len = this.items.length; i < len; i++){
12412                 if(this.items[i] == o) return i;
12413             }
12414             return -1;
12415         }else{
12416             return this.items.indexOf(o);
12417         }
12418     },
12419    
12420 /**
12421  * Returns index within the collection of the passed key.
12422  * @param {String} key The key to find the index of.
12423  * @return {Number} index of the key.
12424  */
12425     indexOfKey : function(key){
12426         if(!this.keys.indexOf){
12427             for(var i = 0, len = this.keys.length; i < len; i++){
12428                 if(this.keys[i] == key) return i;
12429             }
12430             return -1;
12431         }else{
12432             return this.keys.indexOf(key);
12433         }
12434     },
12435    
12436 /**
12437  * Returns the item associated with the passed key OR index. Key has priority over index.
12438  * @param {String/Number} key The key or index of the item.
12439  * @return {Object} The item associated with the passed key.
12440  */
12441     item : function(key){
12442         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12443         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12444     },
12445     
12446 /**
12447  * Returns the item at the specified index.
12448  * @param {Number} index The index of the item.
12449  * @return {Object}
12450  */
12451     itemAt : function(index){
12452         return this.items[index];
12453     },
12454     
12455 /**
12456  * Returns the item associated with the passed key.
12457  * @param {String/Number} key The key of the item.
12458  * @return {Object} The item associated with the passed key.
12459  */
12460     key : function(key){
12461         return this.map[key];
12462     },
12463    
12464 /**
12465  * Returns true if the collection contains the passed Object as an item.
12466  * @param {Object} o  The Object to look for in the collection.
12467  * @return {Boolean} True if the collection contains the Object as an item.
12468  */
12469     contains : function(o){
12470         return this.indexOf(o) != -1;
12471     },
12472    
12473 /**
12474  * Returns true if the collection contains the passed Object as a key.
12475  * @param {String} key The key to look for in the collection.
12476  * @return {Boolean} True if the collection contains the Object as a key.
12477  */
12478     containsKey : function(key){
12479         return typeof this.map[key] != "undefined";
12480     },
12481    
12482 /**
12483  * Removes all items from the collection.
12484  */
12485     clear : function(){
12486         this.length = 0;
12487         this.items = [];
12488         this.keys = [];
12489         this.map = {};
12490         this.fireEvent("clear");
12491     },
12492    
12493 /**
12494  * Returns the first item in the collection.
12495  * @return {Object} the first item in the collection..
12496  */
12497     first : function(){
12498         return this.items[0]; 
12499     },
12500    
12501 /**
12502  * Returns the last item in the collection.
12503  * @return {Object} the last item in the collection..
12504  */
12505     last : function(){
12506         return this.items[this.length-1];   
12507     },
12508     
12509     _sort : function(property, dir, fn){
12510         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12511         fn = fn || function(a, b){
12512             return a-b;
12513         };
12514         var c = [], k = this.keys, items = this.items;
12515         for(var i = 0, len = items.length; i < len; i++){
12516             c[c.length] = {key: k[i], value: items[i], index: i};
12517         }
12518         c.sort(function(a, b){
12519             var v = fn(a[property], b[property]) * dsc;
12520             if(v == 0){
12521                 v = (a.index < b.index ? -1 : 1);
12522             }
12523             return v;
12524         });
12525         for(var i = 0, len = c.length; i < len; i++){
12526             items[i] = c[i].value;
12527             k[i] = c[i].key;
12528         }
12529         this.fireEvent("sort", this);
12530     },
12531     
12532     /**
12533      * Sorts this collection with the passed comparison function
12534      * @param {String} direction (optional) "ASC" or "DESC"
12535      * @param {Function} fn (optional) comparison function
12536      */
12537     sort : function(dir, fn){
12538         this._sort("value", dir, fn);
12539     },
12540     
12541     /**
12542      * Sorts this collection by keys
12543      * @param {String} direction (optional) "ASC" or "DESC"
12544      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12545      */
12546     keySort : function(dir, fn){
12547         this._sort("key", dir, fn || function(a, b){
12548             return String(a).toUpperCase()-String(b).toUpperCase();
12549         });
12550     },
12551     
12552     /**
12553      * Returns a range of items in this collection
12554      * @param {Number} startIndex (optional) defaults to 0
12555      * @param {Number} endIndex (optional) default to the last item
12556      * @return {Array} An array of items
12557      */
12558     getRange : function(start, end){
12559         var items = this.items;
12560         if(items.length < 1){
12561             return [];
12562         }
12563         start = start || 0;
12564         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12565         var r = [];
12566         if(start <= end){
12567             for(var i = start; i <= end; i++) {
12568                     r[r.length] = items[i];
12569             }
12570         }else{
12571             for(var i = start; i >= end; i--) {
12572                     r[r.length] = items[i];
12573             }
12574         }
12575         return r;
12576     },
12577         
12578     /**
12579      * Filter the <i>objects</i> in this collection by a specific property. 
12580      * Returns a new collection that has been filtered.
12581      * @param {String} property A property on your objects
12582      * @param {String/RegExp} value Either string that the property values 
12583      * should start with or a RegExp to test against the property
12584      * @return {MixedCollection} The new filtered collection
12585      */
12586     filter : function(property, value){
12587         if(!value.exec){ // not a regex
12588             value = String(value);
12589             if(value.length == 0){
12590                 return this.clone();
12591             }
12592             value = new RegExp("^" + Roo.escapeRe(value), "i");
12593         }
12594         return this.filterBy(function(o){
12595             return o && value.test(o[property]);
12596         });
12597         },
12598     
12599     /**
12600      * Filter by a function. * Returns a new collection that has been filtered.
12601      * The passed function will be called with each 
12602      * object in the collection. If the function returns true, the value is included 
12603      * otherwise it is filtered.
12604      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12605      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12606      * @return {MixedCollection} The new filtered collection
12607      */
12608     filterBy : function(fn, scope){
12609         var r = new Roo.util.MixedCollection();
12610         r.getKey = this.getKey;
12611         var k = this.keys, it = this.items;
12612         for(var i = 0, len = it.length; i < len; i++){
12613             if(fn.call(scope||this, it[i], k[i])){
12614                                 r.add(k[i], it[i]);
12615                         }
12616         }
12617         return r;
12618     },
12619     
12620     /**
12621      * Creates a duplicate of this collection
12622      * @return {MixedCollection}
12623      */
12624     clone : function(){
12625         var r = new Roo.util.MixedCollection();
12626         var k = this.keys, it = this.items;
12627         for(var i = 0, len = it.length; i < len; i++){
12628             r.add(k[i], it[i]);
12629         }
12630         r.getKey = this.getKey;
12631         return r;
12632     }
12633 });
12634 /**
12635  * Returns the item associated with the passed key or index.
12636  * @method
12637  * @param {String/Number} key The key or index of the item.
12638  * @return {Object} The item associated with the passed key.
12639  */
12640 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
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  * @class Roo.util.JSON
12652  * Modified version of Douglas Crockford"s json.js that doesn"t
12653  * mess with the Object prototype 
12654  * http://www.json.org/js.html
12655  * @singleton
12656  */
12657 Roo.util.JSON = new (function(){
12658     var useHasOwn = {}.hasOwnProperty ? true : false;
12659     
12660     // crashes Safari in some instances
12661     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12662     
12663     var pad = function(n) {
12664         return n < 10 ? "0" + n : n;
12665     };
12666     
12667     var m = {
12668         "\b": '\\b',
12669         "\t": '\\t',
12670         "\n": '\\n',
12671         "\f": '\\f',
12672         "\r": '\\r',
12673         '"' : '\\"',
12674         "\\": '\\\\'
12675     };
12676
12677     var encodeString = function(s){
12678         if (/["\\\x00-\x1f]/.test(s)) {
12679             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12680                 var c = m[b];
12681                 if(c){
12682                     return c;
12683                 }
12684                 c = b.charCodeAt();
12685                 return "\\u00" +
12686                     Math.floor(c / 16).toString(16) +
12687                     (c % 16).toString(16);
12688             }) + '"';
12689         }
12690         return '"' + s + '"';
12691     };
12692     
12693     var encodeArray = function(o){
12694         var a = ["["], b, i, l = o.length, v;
12695             for (i = 0; i < l; i += 1) {
12696                 v = o[i];
12697                 switch (typeof v) {
12698                     case "undefined":
12699                     case "function":
12700                     case "unknown":
12701                         break;
12702                     default:
12703                         if (b) {
12704                             a.push(',');
12705                         }
12706                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12707                         b = true;
12708                 }
12709             }
12710             a.push("]");
12711             return a.join("");
12712     };
12713     
12714     var encodeDate = function(o){
12715         return '"' + o.getFullYear() + "-" +
12716                 pad(o.getMonth() + 1) + "-" +
12717                 pad(o.getDate()) + "T" +
12718                 pad(o.getHours()) + ":" +
12719                 pad(o.getMinutes()) + ":" +
12720                 pad(o.getSeconds()) + '"';
12721     };
12722     
12723     /**
12724      * Encodes an Object, Array or other value
12725      * @param {Mixed} o The variable to encode
12726      * @return {String} The JSON string
12727      */
12728     this.encode = function(o){
12729         if(typeof o == "undefined" || o === null){
12730             return "null";
12731         }else if(o instanceof Array){
12732             return encodeArray(o);
12733         }else if(o instanceof Date){
12734             return encodeDate(o);
12735         }else if(typeof o == "string"){
12736             return encodeString(o);
12737         }else if(typeof o == "number"){
12738             return isFinite(o) ? String(o) : "null";
12739         }else if(typeof o == "boolean"){
12740             return String(o);
12741         }else {
12742             var a = ["{"], b, i, v;
12743             for (i in o) {
12744                 if(!useHasOwn || o.hasOwnProperty(i)) {
12745                     v = o[i];
12746                     switch (typeof v) {
12747                     case "undefined":
12748                     case "function":
12749                     case "unknown":
12750                         break;
12751                     default:
12752                         if(b){
12753                             a.push(',');
12754                         }
12755                         a.push(this.encode(i), ":",
12756                                 v === null ? "null" : this.encode(v));
12757                         b = true;
12758                     }
12759                 }
12760             }
12761             a.push("}");
12762             return a.join("");
12763         }
12764     };
12765     
12766     /**
12767      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12768      * @param {String} json The JSON string
12769      * @return {Object} The resulting object
12770      */
12771     this.decode = function(json){
12772         /**
12773          * eval:var:json
12774          */
12775         return eval("(" + json + ')');
12776     };
12777 })();
12778 /** 
12779  * Shorthand for {@link Roo.util.JSON#encode}
12780  * @member Roo encode 
12781  * @method */
12782 Roo.encode = Roo.util.JSON.encode;
12783 /** 
12784  * Shorthand for {@link Roo.util.JSON#decode}
12785  * @member Roo decode 
12786  * @method */
12787 Roo.decode = Roo.util.JSON.decode;
12788 /*
12789  * Based on:
12790  * Ext JS Library 1.1.1
12791  * Copyright(c) 2006-2007, Ext JS, LLC.
12792  *
12793  * Originally Released Under LGPL - original licence link has changed is not relivant.
12794  *
12795  * Fork - LGPL
12796  * <script type="text/javascript">
12797  */
12798  
12799 /**
12800  * @class Roo.util.Format
12801  * Reusable data formatting functions
12802  * @singleton
12803  */
12804 Roo.util.Format = function(){
12805     var trimRe = /^\s+|\s+$/g;
12806     return {
12807         /**
12808          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12809          * @param {String} value The string to truncate
12810          * @param {Number} length The maximum length to allow before truncating
12811          * @return {String} The converted text
12812          */
12813         ellipsis : function(value, len){
12814             if(value && value.length > len){
12815                 return value.substr(0, len-3)+"...";
12816             }
12817             return value;
12818         },
12819
12820         /**
12821          * Checks a reference and converts it to empty string if it is undefined
12822          * @param {Mixed} value Reference to check
12823          * @return {Mixed} Empty string if converted, otherwise the original value
12824          */
12825         undef : function(value){
12826             return typeof value != "undefined" ? value : "";
12827         },
12828
12829         /**
12830          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12831          * @param {String} value The string to encode
12832          * @return {String} The encoded text
12833          */
12834         htmlEncode : function(value){
12835             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12836         },
12837
12838         /**
12839          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12840          * @param {String} value The string to decode
12841          * @return {String} The decoded text
12842          */
12843         htmlDecode : function(value){
12844             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12845         },
12846
12847         /**
12848          * Trims any whitespace from either side of a string
12849          * @param {String} value The text to trim
12850          * @return {String} The trimmed text
12851          */
12852         trim : function(value){
12853             return String(value).replace(trimRe, "");
12854         },
12855
12856         /**
12857          * Returns a substring from within an original string
12858          * @param {String} value The original text
12859          * @param {Number} start The start index of the substring
12860          * @param {Number} length The length of the substring
12861          * @return {String} The substring
12862          */
12863         substr : function(value, start, length){
12864             return String(value).substr(start, length);
12865         },
12866
12867         /**
12868          * Converts a string to all lower case letters
12869          * @param {String} value The text to convert
12870          * @return {String} The converted text
12871          */
12872         lowercase : function(value){
12873             return String(value).toLowerCase();
12874         },
12875
12876         /**
12877          * Converts a string to all upper case letters
12878          * @param {String} value The text to convert
12879          * @return {String} The converted text
12880          */
12881         uppercase : function(value){
12882             return String(value).toUpperCase();
12883         },
12884
12885         /**
12886          * Converts the first character only of a string to upper case
12887          * @param {String} value The text to convert
12888          * @return {String} The converted text
12889          */
12890         capitalize : function(value){
12891             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12892         },
12893
12894         // private
12895         call : function(value, fn){
12896             if(arguments.length > 2){
12897                 var args = Array.prototype.slice.call(arguments, 2);
12898                 args.unshift(value);
12899                  
12900                 return /** eval:var:value */  eval(fn).apply(window, args);
12901             }else{
12902                 /** eval:var:value */
12903                 return /** eval:var:value */ eval(fn).call(window, value);
12904             }
12905         },
12906
12907         /**
12908          * Format a number as US currency
12909          * @param {Number/String} value The numeric value to format
12910          * @return {String} The formatted currency string
12911          */
12912         usMoney : function(v){
12913             v = (Math.round((v-0)*100))/100;
12914             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12915             v = String(v);
12916             var ps = v.split('.');
12917             var whole = ps[0];
12918             var sub = ps[1] ? '.'+ ps[1] : '.00';
12919             var r = /(\d+)(\d{3})/;
12920             while (r.test(whole)) {
12921                 whole = whole.replace(r, '$1' + ',' + '$2');
12922             }
12923             return "$" + whole + sub ;
12924         },
12925
12926         /**
12927          * Parse a value into a formatted date using the specified format pattern.
12928          * @param {Mixed} value The value to format
12929          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12930          * @return {String} The formatted date string
12931          */
12932         date : function(v, format){
12933             if(!v){
12934                 return "";
12935             }
12936             if(!(v instanceof Date)){
12937                 v = new Date(Date.parse(v));
12938             }
12939             return v.dateFormat(format || "m/d/Y");
12940         },
12941
12942         /**
12943          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12944          * @param {String} format Any valid date format string
12945          * @return {Function} The date formatting function
12946          */
12947         dateRenderer : function(format){
12948             return function(v){
12949                 return Roo.util.Format.date(v, format);  
12950             };
12951         },
12952
12953         // private
12954         stripTagsRE : /<\/?[^>]+>/gi,
12955         
12956         /**
12957          * Strips all HTML tags
12958          * @param {Mixed} value The text from which to strip tags
12959          * @return {String} The stripped text
12960          */
12961         stripTags : function(v){
12962             return !v ? v : String(v).replace(this.stripTagsRE, "");
12963         }
12964     };
12965 }();/*
12966  * Based on:
12967  * Ext JS Library 1.1.1
12968  * Copyright(c) 2006-2007, Ext JS, LLC.
12969  *
12970  * Originally Released Under LGPL - original licence link has changed is not relivant.
12971  *
12972  * Fork - LGPL
12973  * <script type="text/javascript">
12974  */
12975
12976
12977  
12978
12979 /**
12980  * @class Roo.MasterTemplate
12981  * @extends Roo.Template
12982  * Provides a template that can have child templates. The syntax is:
12983 <pre><code>
12984 var t = new Roo.MasterTemplate(
12985         '&lt;select name="{name}"&gt;',
12986                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
12987         '&lt;/select&gt;'
12988 );
12989 t.add('options', {value: 'foo', text: 'bar'});
12990 // or you can add multiple child elements in one shot
12991 t.addAll('options', [
12992     {value: 'foo', text: 'bar'},
12993     {value: 'foo2', text: 'bar2'},
12994     {value: 'foo3', text: 'bar3'}
12995 ]);
12996 // then append, applying the master template values
12997 t.append('my-form', {name: 'my-select'});
12998 </code></pre>
12999 * A name attribute for the child template is not required if you have only one child
13000 * template or you want to refer to them by index.
13001  */
13002 Roo.MasterTemplate = function(){
13003     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13004     this.originalHtml = this.html;
13005     var st = {};
13006     var m, re = this.subTemplateRe;
13007     re.lastIndex = 0;
13008     var subIndex = 0;
13009     while(m = re.exec(this.html)){
13010         var name = m[1], content = m[2];
13011         st[subIndex] = {
13012             name: name,
13013             index: subIndex,
13014             buffer: [],
13015             tpl : new Roo.Template(content)
13016         };
13017         if(name){
13018             st[name] = st[subIndex];
13019         }
13020         st[subIndex].tpl.compile();
13021         st[subIndex].tpl.call = this.call.createDelegate(this);
13022         subIndex++;
13023     }
13024     this.subCount = subIndex;
13025     this.subs = st;
13026 };
13027 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13028     /**
13029     * The regular expression used to match sub templates
13030     * @type RegExp
13031     * @property
13032     */
13033     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13034
13035     /**
13036      * Applies the passed values to a child template.
13037      * @param {String/Number} name (optional) The name or index of the child template
13038      * @param {Array/Object} values The values to be applied to the template
13039      * @return {MasterTemplate} this
13040      */
13041      add : function(name, values){
13042         if(arguments.length == 1){
13043             values = arguments[0];
13044             name = 0;
13045         }
13046         var s = this.subs[name];
13047         s.buffer[s.buffer.length] = s.tpl.apply(values);
13048         return this;
13049     },
13050
13051     /**
13052      * Applies all the passed values to a child template.
13053      * @param {String/Number} name (optional) The name or index of the child template
13054      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13055      * @param {Boolean} reset (optional) True to reset the template first
13056      * @return {MasterTemplate} this
13057      */
13058     fill : function(name, values, reset){
13059         var a = arguments;
13060         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13061             values = a[0];
13062             name = 0;
13063             reset = a[1];
13064         }
13065         if(reset){
13066             this.reset();
13067         }
13068         for(var i = 0, len = values.length; i < len; i++){
13069             this.add(name, values[i]);
13070         }
13071         return this;
13072     },
13073
13074     /**
13075      * Resets the template for reuse
13076      * @return {MasterTemplate} this
13077      */
13078      reset : function(){
13079         var s = this.subs;
13080         for(var i = 0; i < this.subCount; i++){
13081             s[i].buffer = [];
13082         }
13083         return this;
13084     },
13085
13086     applyTemplate : function(values){
13087         var s = this.subs;
13088         var replaceIndex = -1;
13089         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13090             return s[++replaceIndex].buffer.join("");
13091         });
13092         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13093     },
13094
13095     apply : function(){
13096         return this.applyTemplate.apply(this, arguments);
13097     },
13098
13099     compile : function(){return this;}
13100 });
13101
13102 /**
13103  * Alias for fill().
13104  * @method
13105  */
13106 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13107  /**
13108  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13109  * var tpl = Roo.MasterTemplate.from('element-id');
13110  * @param {String/HTMLElement} el
13111  * @param {Object} config
13112  * @static
13113  */
13114 Roo.MasterTemplate.from = function(el, config){
13115     el = Roo.getDom(el);
13116     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13117 };/*
13118  * Based on:
13119  * Ext JS Library 1.1.1
13120  * Copyright(c) 2006-2007, Ext JS, LLC.
13121  *
13122  * Originally Released Under LGPL - original licence link has changed is not relivant.
13123  *
13124  * Fork - LGPL
13125  * <script type="text/javascript">
13126  */
13127
13128  
13129 /**
13130  * @class Roo.util.CSS
13131  * Utility class for manipulating CSS rules
13132  * @singleton
13133  */
13134 Roo.util.CSS = function(){
13135         var rules = null;
13136         var doc = document;
13137
13138     var camelRe = /(-[a-z])/gi;
13139     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13140
13141    return {
13142    /**
13143     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13144     * tag and appended to the HEAD of the document.
13145     * @param {String} cssText The text containing the css rules
13146     * @param {String} id An id to add to the stylesheet for later removal
13147     * @return {StyleSheet}
13148     */
13149    createStyleSheet : function(cssText, id){
13150        var ss;
13151        var head = doc.getElementsByTagName("head")[0];
13152        var rules = doc.createElement("style");
13153        rules.setAttribute("type", "text/css");
13154        if(id){
13155            rules.setAttribute("id", id);
13156        }
13157        if(Roo.isIE){
13158            head.appendChild(rules);
13159            ss = rules.styleSheet;
13160            ss.cssText = cssText;
13161        }else{
13162            try{
13163                 rules.appendChild(doc.createTextNode(cssText));
13164            }catch(e){
13165                rules.cssText = cssText; 
13166            }
13167            head.appendChild(rules);
13168            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13169        }
13170        this.cacheStyleSheet(ss);
13171        return ss;
13172    },
13173
13174    /**
13175     * Removes a style or link tag by id
13176     * @param {String} id The id of the tag
13177     */
13178    removeStyleSheet : function(id){
13179        var existing = doc.getElementById(id);
13180        if(existing){
13181            existing.parentNode.removeChild(existing);
13182        }
13183    },
13184
13185    /**
13186     * Dynamically swaps an existing stylesheet reference for a new one
13187     * @param {String} id The id of an existing link tag to remove
13188     * @param {String} url The href of the new stylesheet to include
13189     */
13190    swapStyleSheet : function(id, url){
13191        this.removeStyleSheet(id);
13192        var ss = doc.createElement("link");
13193        ss.setAttribute("rel", "stylesheet");
13194        ss.setAttribute("type", "text/css");
13195        ss.setAttribute("id", id);
13196        ss.setAttribute("href", url);
13197        doc.getElementsByTagName("head")[0].appendChild(ss);
13198    },
13199    
13200    /**
13201     * Refresh the rule cache if you have dynamically added stylesheets
13202     * @return {Object} An object (hash) of rules indexed by selector
13203     */
13204    refreshCache : function(){
13205        return this.getRules(true);
13206    },
13207
13208    // private
13209    cacheStyleSheet : function(ss){
13210        if(!rules){
13211            rules = {};
13212        }
13213        try{// try catch for cross domain access issue
13214            var ssRules = ss.cssRules || ss.rules;
13215            for(var j = ssRules.length-1; j >= 0; --j){
13216                rules[ssRules[j].selectorText] = ssRules[j];
13217            }
13218        }catch(e){}
13219    },
13220    
13221    /**
13222     * Gets all css rules for the document
13223     * @param {Boolean} refreshCache true to refresh the internal cache
13224     * @return {Object} An object (hash) of rules indexed by selector
13225     */
13226    getRules : function(refreshCache){
13227                 if(rules == null || refreshCache){
13228                         rules = {};
13229                         var ds = doc.styleSheets;
13230                         for(var i =0, len = ds.length; i < len; i++){
13231                             try{
13232                         this.cacheStyleSheet(ds[i]);
13233                     }catch(e){} 
13234                 }
13235                 }
13236                 return rules;
13237         },
13238         
13239         /**
13240     * Gets an an individual CSS rule by selector(s)
13241     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13242     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13243     * @return {CSSRule} The CSS rule or null if one is not found
13244     */
13245    getRule : function(selector, refreshCache){
13246                 var rs = this.getRules(refreshCache);
13247                 if(!(selector instanceof Array)){
13248                     return rs[selector];
13249                 }
13250                 for(var i = 0; i < selector.length; i++){
13251                         if(rs[selector[i]]){
13252                                 return rs[selector[i]];
13253                         }
13254                 }
13255                 return null;
13256         },
13257         
13258         
13259         /**
13260     * Updates a rule property
13261     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13262     * @param {String} property The css property
13263     * @param {String} value The new value for the property
13264     * @return {Boolean} true If a rule was found and updated
13265     */
13266    updateRule : function(selector, property, value){
13267                 if(!(selector instanceof Array)){
13268                         var rule = this.getRule(selector);
13269                         if(rule){
13270                                 rule.style[property.replace(camelRe, camelFn)] = value;
13271                                 return true;
13272                         }
13273                 }else{
13274                         for(var i = 0; i < selector.length; i++){
13275                                 if(this.updateRule(selector[i], property, value)){
13276                                         return true;
13277                                 }
13278                         }
13279                 }
13280                 return false;
13281         }
13282    };   
13283 }();/*
13284  * Based on:
13285  * Ext JS Library 1.1.1
13286  * Copyright(c) 2006-2007, Ext JS, LLC.
13287  *
13288  * Originally Released Under LGPL - original licence link has changed is not relivant.
13289  *
13290  * Fork - LGPL
13291  * <script type="text/javascript">
13292  */
13293
13294  
13295
13296 /**
13297  * @class Roo.util.ClickRepeater
13298  * @extends Roo.util.Observable
13299  * 
13300  * A wrapper class which can be applied to any element. Fires a "click" event while the
13301  * mouse is pressed. The interval between firings may be specified in the config but
13302  * defaults to 10 milliseconds.
13303  * 
13304  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13305  * 
13306  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13307  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13308  * Similar to an autorepeat key delay.
13309  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13310  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13311  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13312  *           "interval" and "delay" are ignored. "immediate" is honored.
13313  * @cfg {Boolean} preventDefault True to prevent the default click event
13314  * @cfg {Boolean} stopDefault True to stop the default click event
13315  * 
13316  * @history
13317  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13318  *     2007-02-02 jvs Renamed to ClickRepeater
13319  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13320  *
13321  *  @constructor
13322  * @param {String/HTMLElement/Element} el The element to listen on
13323  * @param {Object} config
13324  **/
13325 Roo.util.ClickRepeater = function(el, config)
13326 {
13327     this.el = Roo.get(el);
13328     this.el.unselectable();
13329
13330     Roo.apply(this, config);
13331
13332     this.addEvents({
13333     /**
13334      * @event mousedown
13335      * Fires when the mouse button is depressed.
13336      * @param {Roo.util.ClickRepeater} this
13337      */
13338         "mousedown" : true,
13339     /**
13340      * @event click
13341      * Fires on a specified interval during the time the element is pressed.
13342      * @param {Roo.util.ClickRepeater} this
13343      */
13344         "click" : true,
13345     /**
13346      * @event mouseup
13347      * Fires when the mouse key is released.
13348      * @param {Roo.util.ClickRepeater} this
13349      */
13350         "mouseup" : true
13351     });
13352
13353     this.el.on("mousedown", this.handleMouseDown, this);
13354     if(this.preventDefault || this.stopDefault){
13355         this.el.on("click", function(e){
13356             if(this.preventDefault){
13357                 e.preventDefault();
13358             }
13359             if(this.stopDefault){
13360                 e.stopEvent();
13361             }
13362         }, this);
13363     }
13364
13365     // allow inline handler
13366     if(this.handler){
13367         this.on("click", this.handler,  this.scope || this);
13368     }
13369
13370     Roo.util.ClickRepeater.superclass.constructor.call(this);
13371 };
13372
13373 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13374     interval : 20,
13375     delay: 250,
13376     preventDefault : true,
13377     stopDefault : false,
13378     timer : 0,
13379
13380     // private
13381     handleMouseDown : function(){
13382         clearTimeout(this.timer);
13383         this.el.blur();
13384         if(this.pressClass){
13385             this.el.addClass(this.pressClass);
13386         }
13387         this.mousedownTime = new Date();
13388
13389         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13390         this.el.on("mouseout", this.handleMouseOut, this);
13391
13392         this.fireEvent("mousedown", this);
13393         this.fireEvent("click", this);
13394         
13395         this.timer = this.click.defer(this.delay || this.interval, this);
13396     },
13397
13398     // private
13399     click : function(){
13400         this.fireEvent("click", this);
13401         this.timer = this.click.defer(this.getInterval(), this);
13402     },
13403
13404     // private
13405     getInterval: function(){
13406         if(!this.accelerate){
13407             return this.interval;
13408         }
13409         var pressTime = this.mousedownTime.getElapsed();
13410         if(pressTime < 500){
13411             return 400;
13412         }else if(pressTime < 1700){
13413             return 320;
13414         }else if(pressTime < 2600){
13415             return 250;
13416         }else if(pressTime < 3500){
13417             return 180;
13418         }else if(pressTime < 4400){
13419             return 140;
13420         }else if(pressTime < 5300){
13421             return 80;
13422         }else if(pressTime < 6200){
13423             return 50;
13424         }else{
13425             return 10;
13426         }
13427     },
13428
13429     // private
13430     handleMouseOut : function(){
13431         clearTimeout(this.timer);
13432         if(this.pressClass){
13433             this.el.removeClass(this.pressClass);
13434         }
13435         this.el.on("mouseover", this.handleMouseReturn, this);
13436     },
13437
13438     // private
13439     handleMouseReturn : function(){
13440         this.el.un("mouseover", this.handleMouseReturn);
13441         if(this.pressClass){
13442             this.el.addClass(this.pressClass);
13443         }
13444         this.click();
13445     },
13446
13447     // private
13448     handleMouseUp : function(){
13449         clearTimeout(this.timer);
13450         this.el.un("mouseover", this.handleMouseReturn);
13451         this.el.un("mouseout", this.handleMouseOut);
13452         Roo.get(document).un("mouseup", this.handleMouseUp);
13453         this.el.removeClass(this.pressClass);
13454         this.fireEvent("mouseup", this);
13455     }
13456 });/*
13457  * Based on:
13458  * Ext JS Library 1.1.1
13459  * Copyright(c) 2006-2007, Ext JS, LLC.
13460  *
13461  * Originally Released Under LGPL - original licence link has changed is not relivant.
13462  *
13463  * Fork - LGPL
13464  * <script type="text/javascript">
13465  */
13466
13467  
13468 /**
13469  * @class Roo.KeyNav
13470  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13471  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13472  * way to implement custom navigation schemes for any UI component.</p>
13473  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13474  * pageUp, pageDown, del, home, end.  Usage:</p>
13475  <pre><code>
13476 var nav = new Roo.KeyNav("my-element", {
13477     "left" : function(e){
13478         this.moveLeft(e.ctrlKey);
13479     },
13480     "right" : function(e){
13481         this.moveRight(e.ctrlKey);
13482     },
13483     "enter" : function(e){
13484         this.save();
13485     },
13486     scope : this
13487 });
13488 </code></pre>
13489  * @constructor
13490  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13491  * @param {Object} config The config
13492  */
13493 Roo.KeyNav = function(el, config){
13494     this.el = Roo.get(el);
13495     Roo.apply(this, config);
13496     if(!this.disabled){
13497         this.disabled = true;
13498         this.enable();
13499     }
13500 };
13501
13502 Roo.KeyNav.prototype = {
13503     /**
13504      * @cfg {Boolean} disabled
13505      * True to disable this KeyNav instance (defaults to false)
13506      */
13507     disabled : false,
13508     /**
13509      * @cfg {String} defaultEventAction
13510      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13511      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13512      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13513      */
13514     defaultEventAction: "stopEvent",
13515     /**
13516      * @cfg {Boolean} forceKeyDown
13517      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13518      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13519      * handle keydown instead of keypress.
13520      */
13521     forceKeyDown : false,
13522
13523     // private
13524     prepareEvent : function(e){
13525         var k = e.getKey();
13526         var h = this.keyToHandler[k];
13527         //if(h && this[h]){
13528         //    e.stopPropagation();
13529         //}
13530         if(Roo.isSafari && h && k >= 37 && k <= 40){
13531             e.stopEvent();
13532         }
13533     },
13534
13535     // private
13536     relay : function(e){
13537         var k = e.getKey();
13538         var h = this.keyToHandler[k];
13539         if(h && this[h]){
13540             if(this.doRelay(e, this[h], h) !== true){
13541                 e[this.defaultEventAction]();
13542             }
13543         }
13544     },
13545
13546     // private
13547     doRelay : function(e, h, hname){
13548         return h.call(this.scope || this, e);
13549     },
13550
13551     // possible handlers
13552     enter : false,
13553     left : false,
13554     right : false,
13555     up : false,
13556     down : false,
13557     tab : false,
13558     esc : false,
13559     pageUp : false,
13560     pageDown : false,
13561     del : false,
13562     home : false,
13563     end : false,
13564
13565     // quick lookup hash
13566     keyToHandler : {
13567         37 : "left",
13568         39 : "right",
13569         38 : "up",
13570         40 : "down",
13571         33 : "pageUp",
13572         34 : "pageDown",
13573         46 : "del",
13574         36 : "home",
13575         35 : "end",
13576         13 : "enter",
13577         27 : "esc",
13578         9  : "tab"
13579     },
13580
13581         /**
13582          * Enable this KeyNav
13583          */
13584         enable: function(){
13585                 if(this.disabled){
13586             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13587             // the EventObject will normalize Safari automatically
13588             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13589                 this.el.on("keydown", this.relay,  this);
13590             }else{
13591                 this.el.on("keydown", this.prepareEvent,  this);
13592                 this.el.on("keypress", this.relay,  this);
13593             }
13594                     this.disabled = false;
13595                 }
13596         },
13597
13598         /**
13599          * Disable this KeyNav
13600          */
13601         disable: function(){
13602                 if(!this.disabled){
13603                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13604                 this.el.un("keydown", this.relay);
13605             }else{
13606                 this.el.un("keydown", this.prepareEvent);
13607                 this.el.un("keypress", this.relay);
13608             }
13609                     this.disabled = true;
13610                 }
13611         }
13612 };/*
13613  * Based on:
13614  * Ext JS Library 1.1.1
13615  * Copyright(c) 2006-2007, Ext JS, LLC.
13616  *
13617  * Originally Released Under LGPL - original licence link has changed is not relivant.
13618  *
13619  * Fork - LGPL
13620  * <script type="text/javascript">
13621  */
13622
13623  
13624 /**
13625  * @class Roo.KeyMap
13626  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13627  * The constructor accepts the same config object as defined by {@link #addBinding}.
13628  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13629  * combination it will call the function with this signature (if the match is a multi-key
13630  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13631  * A KeyMap can also handle a string representation of keys.<br />
13632  * Usage:
13633  <pre><code>
13634 // map one key by key code
13635 var map = new Roo.KeyMap("my-element", {
13636     key: 13, // or Roo.EventObject.ENTER
13637     fn: myHandler,
13638     scope: myObject
13639 });
13640
13641 // map multiple keys to one action by string
13642 var map = new Roo.KeyMap("my-element", {
13643     key: "a\r\n\t",
13644     fn: myHandler,
13645     scope: myObject
13646 });
13647
13648 // map multiple keys to multiple actions by strings and array of codes
13649 var map = new Roo.KeyMap("my-element", [
13650     {
13651         key: [10,13],
13652         fn: function(){ alert("Return was pressed"); }
13653     }, {
13654         key: "abc",
13655         fn: function(){ alert('a, b or c was pressed'); }
13656     }, {
13657         key: "\t",
13658         ctrl:true,
13659         shift:true,
13660         fn: function(){ alert('Control + shift + tab was pressed.'); }
13661     }
13662 ]);
13663 </code></pre>
13664  * <b>Note: A KeyMap starts enabled</b>
13665  * @constructor
13666  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13667  * @param {Object} config The config (see {@link #addBinding})
13668  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13669  */
13670 Roo.KeyMap = function(el, config, eventName){
13671     this.el  = Roo.get(el);
13672     this.eventName = eventName || "keydown";
13673     this.bindings = [];
13674     if(config){
13675         this.addBinding(config);
13676     }
13677     this.enable();
13678 };
13679
13680 Roo.KeyMap.prototype = {
13681     /**
13682      * True to stop the event from bubbling and prevent the default browser action if the
13683      * key was handled by the KeyMap (defaults to false)
13684      * @type Boolean
13685      */
13686     stopEvent : false,
13687
13688     /**
13689      * Add a new binding to this KeyMap. The following config object properties are supported:
13690      * <pre>
13691 Property    Type             Description
13692 ----------  ---------------  ----------------------------------------------------------------------
13693 key         String/Array     A single keycode or an array of keycodes to handle
13694 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13695 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13696 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13697 fn          Function         The function to call when KeyMap finds the expected key combination
13698 scope       Object           The scope of the callback function
13699 </pre>
13700      *
13701      * Usage:
13702      * <pre><code>
13703 // Create a KeyMap
13704 var map = new Roo.KeyMap(document, {
13705     key: Roo.EventObject.ENTER,
13706     fn: handleKey,
13707     scope: this
13708 });
13709
13710 //Add a new binding to the existing KeyMap later
13711 map.addBinding({
13712     key: 'abc',
13713     shift: true,
13714     fn: handleKey,
13715     scope: this
13716 });
13717 </code></pre>
13718      * @param {Object/Array} config A single KeyMap config or an array of configs
13719      */
13720         addBinding : function(config){
13721         if(config instanceof Array){
13722             for(var i = 0, len = config.length; i < len; i++){
13723                 this.addBinding(config[i]);
13724             }
13725             return;
13726         }
13727         var keyCode = config.key,
13728             shift = config.shift, 
13729             ctrl = config.ctrl, 
13730             alt = config.alt,
13731             fn = config.fn,
13732             scope = config.scope;
13733         if(typeof keyCode == "string"){
13734             var ks = [];
13735             var keyString = keyCode.toUpperCase();
13736             for(var j = 0, len = keyString.length; j < len; j++){
13737                 ks.push(keyString.charCodeAt(j));
13738             }
13739             keyCode = ks;
13740         }
13741         var keyArray = keyCode instanceof Array;
13742         var handler = function(e){
13743             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13744                 var k = e.getKey();
13745                 if(keyArray){
13746                     for(var i = 0, len = keyCode.length; i < len; i++){
13747                         if(keyCode[i] == k){
13748                           if(this.stopEvent){
13749                               e.stopEvent();
13750                           }
13751                           fn.call(scope || window, k, e);
13752                           return;
13753                         }
13754                     }
13755                 }else{
13756                     if(k == keyCode){
13757                         if(this.stopEvent){
13758                            e.stopEvent();
13759                         }
13760                         fn.call(scope || window, k, e);
13761                     }
13762                 }
13763             }
13764         };
13765         this.bindings.push(handler);  
13766         },
13767
13768     /**
13769      * Shorthand for adding a single key listener
13770      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13771      * following options:
13772      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13773      * @param {Function} fn The function to call
13774      * @param {Object} scope (optional) The scope of the function
13775      */
13776     on : function(key, fn, scope){
13777         var keyCode, shift, ctrl, alt;
13778         if(typeof key == "object" && !(key instanceof Array)){
13779             keyCode = key.key;
13780             shift = key.shift;
13781             ctrl = key.ctrl;
13782             alt = key.alt;
13783         }else{
13784             keyCode = key;
13785         }
13786         this.addBinding({
13787             key: keyCode,
13788             shift: shift,
13789             ctrl: ctrl,
13790             alt: alt,
13791             fn: fn,
13792             scope: scope
13793         })
13794     },
13795
13796     // private
13797     handleKeyDown : function(e){
13798             if(this.enabled){ //just in case
13799             var b = this.bindings;
13800             for(var i = 0, len = b.length; i < len; i++){
13801                 b[i].call(this, e);
13802             }
13803             }
13804         },
13805         
13806         /**
13807          * Returns true if this KeyMap is enabled
13808          * @return {Boolean} 
13809          */
13810         isEnabled : function(){
13811             return this.enabled;  
13812         },
13813         
13814         /**
13815          * Enables this KeyMap
13816          */
13817         enable: function(){
13818                 if(!this.enabled){
13819                     this.el.on(this.eventName, this.handleKeyDown, this);
13820                     this.enabled = true;
13821                 }
13822         },
13823
13824         /**
13825          * Disable this KeyMap
13826          */
13827         disable: function(){
13828                 if(this.enabled){
13829                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
13830                     this.enabled = false;
13831                 }
13832         }
13833 };/*
13834  * Based on:
13835  * Ext JS Library 1.1.1
13836  * Copyright(c) 2006-2007, Ext JS, LLC.
13837  *
13838  * Originally Released Under LGPL - original licence link has changed is not relivant.
13839  *
13840  * Fork - LGPL
13841  * <script type="text/javascript">
13842  */
13843
13844  
13845 /**
13846  * @class Roo.util.TextMetrics
13847  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13848  * wide, in pixels, a given block of text will be.
13849  * @singleton
13850  */
13851 Roo.util.TextMetrics = function(){
13852     var shared;
13853     return {
13854         /**
13855          * Measures the size of the specified text
13856          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13857          * that can affect the size of the rendered text
13858          * @param {String} text The text to measure
13859          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13860          * in order to accurately measure the text height
13861          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13862          */
13863         measure : function(el, text, fixedWidth){
13864             if(!shared){
13865                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13866             }
13867             shared.bind(el);
13868             shared.setFixedWidth(fixedWidth || 'auto');
13869             return shared.getSize(text);
13870         },
13871
13872         /**
13873          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
13874          * the overhead of multiple calls to initialize the style properties on each measurement.
13875          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13876          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13877          * in order to accurately measure the text height
13878          * @return {Roo.util.TextMetrics.Instance} instance The new instance
13879          */
13880         createInstance : function(el, fixedWidth){
13881             return Roo.util.TextMetrics.Instance(el, fixedWidth);
13882         }
13883     };
13884 }();
13885
13886  
13887
13888 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13889     var ml = new Roo.Element(document.createElement('div'));
13890     document.body.appendChild(ml.dom);
13891     ml.position('absolute');
13892     ml.setLeftTop(-1000, -1000);
13893     ml.hide();
13894
13895     if(fixedWidth){
13896         ml.setWidth(fixedWidth);
13897     }
13898      
13899     var instance = {
13900         /**
13901          * Returns the size of the specified text based on the internal element's style and width properties
13902          * @memberOf Roo.util.TextMetrics.Instance#
13903          * @param {String} text The text to measure
13904          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13905          */
13906         getSize : function(text){
13907             ml.update(text);
13908             var s = ml.getSize();
13909             ml.update('');
13910             return s;
13911         },
13912
13913         /**
13914          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13915          * that can affect the size of the rendered text
13916          * @memberOf Roo.util.TextMetrics.Instance#
13917          * @param {String/HTMLElement} el The element, dom node or id
13918          */
13919         bind : function(el){
13920             ml.setStyle(
13921                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13922             );
13923         },
13924
13925         /**
13926          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
13927          * to set a fixed width in order to accurately measure the text height.
13928          * @memberOf Roo.util.TextMetrics.Instance#
13929          * @param {Number} width The width to set on the element
13930          */
13931         setFixedWidth : function(width){
13932             ml.setWidth(width);
13933         },
13934
13935         /**
13936          * Returns the measured width of the specified text
13937          * @memberOf Roo.util.TextMetrics.Instance#
13938          * @param {String} text The text to measure
13939          * @return {Number} width The width in pixels
13940          */
13941         getWidth : function(text){
13942             ml.dom.style.width = 'auto';
13943             return this.getSize(text).width;
13944         },
13945
13946         /**
13947          * Returns the measured height of the specified text.  For multiline text, be sure to call
13948          * {@link #setFixedWidth} if necessary.
13949          * @memberOf Roo.util.TextMetrics.Instance#
13950          * @param {String} text The text to measure
13951          * @return {Number} height The height in pixels
13952          */
13953         getHeight : function(text){
13954             return this.getSize(text).height;
13955         }
13956     };
13957
13958     instance.bind(bindTo);
13959
13960     return instance;
13961 };
13962
13963 // backwards compat
13964 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13965  * Based on:
13966  * Ext JS Library 1.1.1
13967  * Copyright(c) 2006-2007, Ext JS, LLC.
13968  *
13969  * Originally Released Under LGPL - original licence link has changed is not relivant.
13970  *
13971  * Fork - LGPL
13972  * <script type="text/javascript">
13973  */
13974
13975 /**
13976  * @class Roo.state.Provider
13977  * Abstract base class for state provider implementations. This class provides methods
13978  * for encoding and decoding <b>typed</b> variables including dates and defines the 
13979  * Provider interface.
13980  */
13981 Roo.state.Provider = function(){
13982     /**
13983      * @event statechange
13984      * Fires when a state change occurs.
13985      * @param {Provider} this This state provider
13986      * @param {String} key The state key which was changed
13987      * @param {String} value The encoded value for the state
13988      */
13989     this.addEvents({
13990         "statechange": true
13991     });
13992     this.state = {};
13993     Roo.state.Provider.superclass.constructor.call(this);
13994 };
13995 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13996     /**
13997      * Returns the current value for a key
13998      * @param {String} name The key name
13999      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14000      * @return {Mixed} The state data
14001      */
14002     get : function(name, defaultValue){
14003         return typeof this.state[name] == "undefined" ?
14004             defaultValue : this.state[name];
14005     },
14006     
14007     /**
14008      * Clears a value from the state
14009      * @param {String} name The key name
14010      */
14011     clear : function(name){
14012         delete this.state[name];
14013         this.fireEvent("statechange", this, name, null);
14014     },
14015     
14016     /**
14017      * Sets the value for a key
14018      * @param {String} name The key name
14019      * @param {Mixed} value The value to set
14020      */
14021     set : function(name, value){
14022         this.state[name] = value;
14023         this.fireEvent("statechange", this, name, value);
14024     },
14025     
14026     /**
14027      * Decodes a string previously encoded with {@link #encodeValue}.
14028      * @param {String} value The value to decode
14029      * @return {Mixed} The decoded value
14030      */
14031     decodeValue : function(cookie){
14032         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14033         var matches = re.exec(unescape(cookie));
14034         if(!matches || !matches[1]) return; // non state cookie
14035         var type = matches[1];
14036         var v = matches[2];
14037         switch(type){
14038             case "n":
14039                 return parseFloat(v);
14040             case "d":
14041                 return new Date(Date.parse(v));
14042             case "b":
14043                 return (v == "1");
14044             case "a":
14045                 var all = [];
14046                 var values = v.split("^");
14047                 for(var i = 0, len = values.length; i < len; i++){
14048                     all.push(this.decodeValue(values[i]));
14049                 }
14050                 return all;
14051            case "o":
14052                 var all = {};
14053                 var values = v.split("^");
14054                 for(var i = 0, len = values.length; i < len; i++){
14055                     var kv = values[i].split("=");
14056                     all[kv[0]] = this.decodeValue(kv[1]);
14057                 }
14058                 return all;
14059            default:
14060                 return v;
14061         }
14062     },
14063     
14064     /**
14065      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14066      * @param {Mixed} value The value to encode
14067      * @return {String} The encoded value
14068      */
14069     encodeValue : function(v){
14070         var enc;
14071         if(typeof v == "number"){
14072             enc = "n:" + v;
14073         }else if(typeof v == "boolean"){
14074             enc = "b:" + (v ? "1" : "0");
14075         }else if(v instanceof Date){
14076             enc = "d:" + v.toGMTString();
14077         }else if(v instanceof Array){
14078             var flat = "";
14079             for(var i = 0, len = v.length; i < len; i++){
14080                 flat += this.encodeValue(v[i]);
14081                 if(i != len-1) flat += "^";
14082             }
14083             enc = "a:" + flat;
14084         }else if(typeof v == "object"){
14085             var flat = "";
14086             for(var key in v){
14087                 if(typeof v[key] != "function"){
14088                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14089                 }
14090             }
14091             enc = "o:" + flat.substring(0, flat.length-1);
14092         }else{
14093             enc = "s:" + v;
14094         }
14095         return escape(enc);        
14096     }
14097 });
14098
14099 /*
14100  * Based on:
14101  * Ext JS Library 1.1.1
14102  * Copyright(c) 2006-2007, Ext JS, LLC.
14103  *
14104  * Originally Released Under LGPL - original licence link has changed is not relivant.
14105  *
14106  * Fork - LGPL
14107  * <script type="text/javascript">
14108  */
14109 /**
14110  * @class Roo.state.Manager
14111  * This is the global state manager. By default all components that are "state aware" check this class
14112  * for state information if you don't pass them a custom state provider. In order for this class
14113  * to be useful, it must be initialized with a provider when your application initializes.
14114  <pre><code>
14115 // in your initialization function
14116 init : function(){
14117    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14118    ...
14119    // supposed you have a {@link Roo.BorderLayout}
14120    var layout = new Roo.BorderLayout(...);
14121    layout.restoreState();
14122    // or a {Roo.BasicDialog}
14123    var dialog = new Roo.BasicDialog(...);
14124    dialog.restoreState();
14125  </code></pre>
14126  * @singleton
14127  */
14128 Roo.state.Manager = function(){
14129     var provider = new Roo.state.Provider();
14130     
14131     return {
14132         /**
14133          * Configures the default state provider for your application
14134          * @param {Provider} stateProvider The state provider to set
14135          */
14136         setProvider : function(stateProvider){
14137             provider = stateProvider;
14138         },
14139         
14140         /**
14141          * Returns the current value for a key
14142          * @param {String} name The key name
14143          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14144          * @return {Mixed} The state data
14145          */
14146         get : function(key, defaultValue){
14147             return provider.get(key, defaultValue);
14148         },
14149         
14150         /**
14151          * Sets the value for a key
14152          * @param {String} name The key name
14153          * @param {Mixed} value The state data
14154          */
14155          set : function(key, value){
14156             provider.set(key, value);
14157         },
14158         
14159         /**
14160          * Clears a value from the state
14161          * @param {String} name The key name
14162          */
14163         clear : function(key){
14164             provider.clear(key);
14165         },
14166         
14167         /**
14168          * Gets the currently configured state provider
14169          * @return {Provider} The state provider
14170          */
14171         getProvider : function(){
14172             return provider;
14173         }
14174     };
14175 }();
14176 /*
14177  * Based on:
14178  * Ext JS Library 1.1.1
14179  * Copyright(c) 2006-2007, Ext JS, LLC.
14180  *
14181  * Originally Released Under LGPL - original licence link has changed is not relivant.
14182  *
14183  * Fork - LGPL
14184  * <script type="text/javascript">
14185  */
14186 /**
14187  * @class Roo.state.CookieProvider
14188  * @extends Roo.state.Provider
14189  * The default Provider implementation which saves state via cookies.
14190  * <br />Usage:
14191  <pre><code>
14192    var cp = new Roo.state.CookieProvider({
14193        path: "/cgi-bin/",
14194        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14195        domain: "roojs.com"
14196    })
14197    Roo.state.Manager.setProvider(cp);
14198  </code></pre>
14199  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14200  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14201  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14202  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14203  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14204  * domain the page is running on including the 'www' like 'www.roojs.com')
14205  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14206  * @constructor
14207  * Create a new CookieProvider
14208  * @param {Object} config The configuration object
14209  */
14210 Roo.state.CookieProvider = function(config){
14211     Roo.state.CookieProvider.superclass.constructor.call(this);
14212     this.path = "/";
14213     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14214     this.domain = null;
14215     this.secure = false;
14216     Roo.apply(this, config);
14217     this.state = this.readCookies();
14218 };
14219
14220 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14221     // private
14222     set : function(name, value){
14223         if(typeof value == "undefined" || value === null){
14224             this.clear(name);
14225             return;
14226         }
14227         this.setCookie(name, value);
14228         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14229     },
14230
14231     // private
14232     clear : function(name){
14233         this.clearCookie(name);
14234         Roo.state.CookieProvider.superclass.clear.call(this, name);
14235     },
14236
14237     // private
14238     readCookies : function(){
14239         var cookies = {};
14240         var c = document.cookie + ";";
14241         var re = /\s?(.*?)=(.*?);/g;
14242         var matches;
14243         while((matches = re.exec(c)) != null){
14244             var name = matches[1];
14245             var value = matches[2];
14246             if(name && name.substring(0,3) == "ys-"){
14247                 cookies[name.substr(3)] = this.decodeValue(value);
14248             }
14249         }
14250         return cookies;
14251     },
14252
14253     // private
14254     setCookie : function(name, value){
14255         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14256            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14257            ((this.path == null) ? "" : ("; path=" + this.path)) +
14258            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14259            ((this.secure == true) ? "; secure" : "");
14260     },
14261
14262     // private
14263     clearCookie : function(name){
14264         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14265            ((this.path == null) ? "" : ("; path=" + this.path)) +
14266            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14267            ((this.secure == true) ? "; secure" : "");
14268     }
14269 });