Roo/Template.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 )
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  * Based on:
873  * Ext JS Library 1.1.1
874  * Copyright(c) 2006-2007, Ext JS, LLC.
875  *
876  * Originally Released Under LGPL - original licence link has changed is not relivant.
877  *
878  * Fork - LGPL
879  * <script type="text/javascript">
880  */
881
882 /**
883  * @class Date
884  *
885  * The date parsing and format syntax is a subset of
886  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
887  * supported will provide results equivalent to their PHP versions.
888  *
889  * Following is the list of all currently supported formats:
890  *<pre>
891 Sample date:
892 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
893
894 Format  Output      Description
895 ------  ----------  --------------------------------------------------------------
896   d      10         Day of the month, 2 digits with leading zeros
897   D      Wed        A textual representation of a day, three letters
898   j      10         Day of the month without leading zeros
899   l      Wednesday  A full textual representation of the day of the week
900   S      th         English ordinal day of month suffix, 2 chars (use with j)
901   w      3          Numeric representation of the day of the week
902   z      9          The julian date, or day of the year (0-365)
903   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
904   F      January    A full textual representation of the month
905   m      01         Numeric representation of a month, with leading zeros
906   M      Jan        Month name abbreviation, three letters
907   n      1          Numeric representation of a month, without leading zeros
908   t      31         Number of days in the given month
909   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
910   Y      2007       A full numeric representation of a year, 4 digits
911   y      07         A two digit representation of a year
912   a      pm         Lowercase Ante meridiem and Post meridiem
913   A      PM         Uppercase Ante meridiem and Post meridiem
914   g      3          12-hour format of an hour without leading zeros
915   G      15         24-hour format of an hour without leading zeros
916   h      03         12-hour format of an hour with leading zeros
917   H      15         24-hour format of an hour with leading zeros
918   i      05         Minutes with leading zeros
919   s      01         Seconds, with leading zeros
920   O      -0600      Difference to Greenwich time (GMT) in hours
921   T      CST        Timezone setting of the machine running the code
922   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
923 </pre>
924  *
925  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
926  * <pre><code>
927 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
928 document.write(dt.format('Y-m-d'));                         //2007-01-10
929 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
930 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
931  </code></pre>
932  *
933  * Here are some standard date/time patterns that you might find helpful.  They
934  * are not part of the source of Date.js, but to use them you can simply copy this
935  * block of code into any script that is included after Date.js and they will also become
936  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
937  * <pre><code>
938 Date.patterns = {
939     ISO8601Long:"Y-m-d H:i:s",
940     ISO8601Short:"Y-m-d",
941     ShortDate: "n/j/Y",
942     LongDate: "l, F d, Y",
943     FullDateTime: "l, F d, Y g:i:s A",
944     MonthDay: "F d",
945     ShortTime: "g:i A",
946     LongTime: "g:i:s A",
947     SortableDateTime: "Y-m-d\\TH:i:s",
948     UniversalSortableDateTime: "Y-m-d H:i:sO",
949     YearMonth: "F, Y"
950 };
951 </code></pre>
952  *
953  * Example usage:
954  * <pre><code>
955 var dt = new Date();
956 document.write(dt.format(Date.patterns.ShortDate));
957  </code></pre>
958  */
959
960 /*
961  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
962  * They generate precompiled functions from date formats instead of parsing and
963  * processing the pattern every time you format a date.  These functions are available
964  * on every Date object (any javascript function).
965  *
966  * The original article and download are here:
967  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
968  *
969  */
970  
971  
972  // was in core
973 /**
974  Returns the number of milliseconds between this date and date
975  @param {Date} date (optional) Defaults to now
976  @return {Number} The diff in milliseconds
977  @member Date getElapsed
978  */
979 Date.prototype.getElapsed = function(date) {
980         return Math.abs((date || new Date()).getTime()-this.getTime());
981 };
982 // was in date file..
983
984
985 // private
986 Date.parseFunctions = {count:0};
987 // private
988 Date.parseRegexes = [];
989 // private
990 Date.formatFunctions = {count:0};
991
992 // private
993 Date.prototype.dateFormat = function(format) {
994     if (Date.formatFunctions[format] == null) {
995         Date.createNewFormat(format);
996     }
997     var func = Date.formatFunctions[format];
998     return this[func]();
999 };
1000
1001
1002 /**
1003  * Formats a date given the supplied format string
1004  * @param {String} format The format string
1005  * @return {String} The formatted date
1006  * @method
1007  */
1008 Date.prototype.format = Date.prototype.dateFormat;
1009
1010 // private
1011 Date.createNewFormat = function(format) {
1012     var funcName = "format" + Date.formatFunctions.count++;
1013     Date.formatFunctions[format] = funcName;
1014     var code = "Date.prototype." + funcName + " = function(){return ";
1015     var special = false;
1016     var ch = '';
1017     for (var i = 0; i < format.length; ++i) {
1018         ch = format.charAt(i);
1019         if (!special && ch == "\\") {
1020             special = true;
1021         }
1022         else if (special) {
1023             special = false;
1024             code += "'" + String.escape(ch) + "' + ";
1025         }
1026         else {
1027             code += Date.getFormatCode(ch);
1028         }
1029     }
1030     /** eval:var:zzzzzzzzzzzzz */
1031     eval(code.substring(0, code.length - 3) + ";}");
1032 };
1033
1034 // private
1035 Date.getFormatCode = function(character) {
1036     switch (character) {
1037     case "d":
1038         return "String.leftPad(this.getDate(), 2, '0') + ";
1039     case "D":
1040         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1041     case "j":
1042         return "this.getDate() + ";
1043     case "l":
1044         return "Date.dayNames[this.getDay()] + ";
1045     case "S":
1046         return "this.getSuffix() + ";
1047     case "w":
1048         return "this.getDay() + ";
1049     case "z":
1050         return "this.getDayOfYear() + ";
1051     case "W":
1052         return "this.getWeekOfYear() + ";
1053     case "F":
1054         return "Date.monthNames[this.getMonth()] + ";
1055     case "m":
1056         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1057     case "M":
1058         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1059     case "n":
1060         return "(this.getMonth() + 1) + ";
1061     case "t":
1062         return "this.getDaysInMonth() + ";
1063     case "L":
1064         return "(this.isLeapYear() ? 1 : 0) + ";
1065     case "Y":
1066         return "this.getFullYear() + ";
1067     case "y":
1068         return "('' + this.getFullYear()).substring(2, 4) + ";
1069     case "a":
1070         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1071     case "A":
1072         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1073     case "g":
1074         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1075     case "G":
1076         return "this.getHours() + ";
1077     case "h":
1078         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1079     case "H":
1080         return "String.leftPad(this.getHours(), 2, '0') + ";
1081     case "i":
1082         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1083     case "s":
1084         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1085     case "O":
1086         return "this.getGMTOffset() + ";
1087     case "T":
1088         return "this.getTimezone() + ";
1089     case "Z":
1090         return "(this.getTimezoneOffset() * -60) + ";
1091     default:
1092         return "'" + String.escape(character) + "' + ";
1093     }
1094 };
1095
1096 /**
1097  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1098  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1099  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1100  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1101  * string or the parse operation will fail.
1102  * Example Usage:
1103 <pre><code>
1104 //dt = Fri May 25 2007 (current date)
1105 var dt = new Date();
1106
1107 //dt = Thu May 25 2006 (today's month/day in 2006)
1108 dt = Date.parseDate("2006", "Y");
1109
1110 //dt = Sun Jan 15 2006 (all date parts specified)
1111 dt = Date.parseDate("2006-1-15", "Y-m-d");
1112
1113 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1114 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1115 </code></pre>
1116  * @param {String} input The unparsed date as a string
1117  * @param {String} format The format the date is in
1118  * @return {Date} The parsed date
1119  * @static
1120  */
1121 Date.parseDate = function(input, format) {
1122     if (Date.parseFunctions[format] == null) {
1123         Date.createParser(format);
1124     }
1125     var func = Date.parseFunctions[format];
1126     return Date[func](input);
1127 };
1128 /**
1129  * @private
1130  */
1131 Date.createParser = function(format) {
1132     var funcName = "parse" + Date.parseFunctions.count++;
1133     var regexNum = Date.parseRegexes.length;
1134     var currentGroup = 1;
1135     Date.parseFunctions[format] = funcName;
1136
1137     var code = "Date." + funcName + " = function(input){\n"
1138         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1139         + "var d = new Date();\n"
1140         + "y = d.getFullYear();\n"
1141         + "m = d.getMonth();\n"
1142         + "d = d.getDate();\n"
1143         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1144         + "if (results && results.length > 0) {";
1145     var regex = "";
1146
1147     var special = false;
1148     var ch = '';
1149     for (var i = 0; i < format.length; ++i) {
1150         ch = format.charAt(i);
1151         if (!special && ch == "\\") {
1152             special = true;
1153         }
1154         else if (special) {
1155             special = false;
1156             regex += String.escape(ch);
1157         }
1158         else {
1159             var obj = Date.formatCodeToRegex(ch, currentGroup);
1160             currentGroup += obj.g;
1161             regex += obj.s;
1162             if (obj.g && obj.c) {
1163                 code += obj.c;
1164             }
1165         }
1166     }
1167
1168     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1169         + "{v = new Date(y, m, d, h, i, s);}\n"
1170         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1171         + "{v = new Date(y, m, d, h, i);}\n"
1172         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1173         + "{v = new Date(y, m, d, h);}\n"
1174         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1175         + "{v = new Date(y, m, d);}\n"
1176         + "else if (y >= 0 && m >= 0)\n"
1177         + "{v = new Date(y, m);}\n"
1178         + "else if (y >= 0)\n"
1179         + "{v = new Date(y);}\n"
1180         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1181         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1182         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1183         + ";}";
1184
1185     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1186     /** eval:var:zzzzzzzzzzzzz */
1187     eval(code);
1188 };
1189
1190 // private
1191 Date.formatCodeToRegex = function(character, currentGroup) {
1192     switch (character) {
1193     case "D":
1194         return {g:0,
1195         c:null,
1196         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1197     case "j":
1198         return {g:1,
1199             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1200             s:"(\\d{1,2})"}; // day of month without leading zeroes
1201     case "d":
1202         return {g:1,
1203             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1204             s:"(\\d{2})"}; // day of month with leading zeroes
1205     case "l":
1206         return {g:0,
1207             c:null,
1208             s:"(?:" + Date.dayNames.join("|") + ")"};
1209     case "S":
1210         return {g:0,
1211             c:null,
1212             s:"(?:st|nd|rd|th)"};
1213     case "w":
1214         return {g:0,
1215             c:null,
1216             s:"\\d"};
1217     case "z":
1218         return {g:0,
1219             c:null,
1220             s:"(?:\\d{1,3})"};
1221     case "W":
1222         return {g:0,
1223             c:null,
1224             s:"(?:\\d{2})"};
1225     case "F":
1226         return {g:1,
1227             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1228             s:"(" + Date.monthNames.join("|") + ")"};
1229     case "M":
1230         return {g:1,
1231             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1232             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1233     case "n":
1234         return {g:1,
1235             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1236             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1237     case "m":
1238         return {g:1,
1239             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1240             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1241     case "t":
1242         return {g:0,
1243             c:null,
1244             s:"\\d{1,2}"};
1245     case "L":
1246         return {g:0,
1247             c:null,
1248             s:"(?:1|0)"};
1249     case "Y":
1250         return {g:1,
1251             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1252             s:"(\\d{4})"};
1253     case "y":
1254         return {g:1,
1255             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1256                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1257             s:"(\\d{1,2})"};
1258     case "a":
1259         return {g:1,
1260             c:"if (results[" + currentGroup + "] == 'am') {\n"
1261                 + "if (h == 12) { h = 0; }\n"
1262                 + "} else { if (h < 12) { h += 12; }}",
1263             s:"(am|pm)"};
1264     case "A":
1265         return {g:1,
1266             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1267                 + "if (h == 12) { h = 0; }\n"
1268                 + "} else { if (h < 12) { h += 12; }}",
1269             s:"(AM|PM)"};
1270     case "g":
1271     case "G":
1272         return {g:1,
1273             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1274             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1275     case "h":
1276     case "H":
1277         return {g:1,
1278             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1279             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1280     case "i":
1281         return {g:1,
1282             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1283             s:"(\\d{2})"};
1284     case "s":
1285         return {g:1,
1286             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1287             s:"(\\d{2})"};
1288     case "O":
1289         return {g:1,
1290             c:[
1291                 "o = results[", currentGroup, "];\n",
1292                 "var sn = o.substring(0,1);\n", // get + / - sign
1293                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1294                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1295                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1296                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1297             ].join(""),
1298             s:"([+\-]\\d{4})"};
1299     case "T":
1300         return {g:0,
1301             c:null,
1302             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1303     case "Z":
1304         return {g:1,
1305             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1306                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1307             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1308     default:
1309         return {g:0,
1310             c:null,
1311             s:String.escape(character)};
1312     }
1313 };
1314
1315 /**
1316  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1317  * @return {String} The abbreviated timezone name (e.g. 'CST')
1318  */
1319 Date.prototype.getTimezone = function() {
1320     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1321 };
1322
1323 /**
1324  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1325  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1326  */
1327 Date.prototype.getGMTOffset = function() {
1328     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1329         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1330         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1331 };
1332
1333 /**
1334  * Get the numeric day number of the year, adjusted for leap year.
1335  * @return {Number} 0 through 364 (365 in leap years)
1336  */
1337 Date.prototype.getDayOfYear = function() {
1338     var num = 0;
1339     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1340     for (var i = 0; i < this.getMonth(); ++i) {
1341         num += Date.daysInMonth[i];
1342     }
1343     return num + this.getDate() - 1;
1344 };
1345
1346 /**
1347  * Get the string representation of the numeric week number of the year
1348  * (equivalent to the format specifier 'W').
1349  * @return {String} '00' through '52'
1350  */
1351 Date.prototype.getWeekOfYear = function() {
1352     // Skip to Thursday of this week
1353     var now = this.getDayOfYear() + (4 - this.getDay());
1354     // Find the first Thursday of the year
1355     var jan1 = new Date(this.getFullYear(), 0, 1);
1356     var then = (7 - jan1.getDay() + 4);
1357     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1358 };
1359
1360 /**
1361  * Whether or not the current date is in a leap year.
1362  * @return {Boolean} True if the current date is in a leap year, else false
1363  */
1364 Date.prototype.isLeapYear = function() {
1365     var year = this.getFullYear();
1366     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1367 };
1368
1369 /**
1370  * Get the first day of the current month, adjusted for leap year.  The returned value
1371  * is the numeric day index within the week (0-6) which can be used in conjunction with
1372  * the {@link #monthNames} array to retrieve the textual day name.
1373  * Example:
1374  *<pre><code>
1375 var dt = new Date('1/10/2007');
1376 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1377 </code></pre>
1378  * @return {Number} The day number (0-6)
1379  */
1380 Date.prototype.getFirstDayOfMonth = function() {
1381     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1382     return (day < 0) ? (day + 7) : day;
1383 };
1384
1385 /**
1386  * Get the last day of the current month, adjusted for leap year.  The returned value
1387  * is the numeric day index within the week (0-6) which can be used in conjunction with
1388  * the {@link #monthNames} array to retrieve the textual day name.
1389  * Example:
1390  *<pre><code>
1391 var dt = new Date('1/10/2007');
1392 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1393 </code></pre>
1394  * @return {Number} The day number (0-6)
1395  */
1396 Date.prototype.getLastDayOfMonth = function() {
1397     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1398     return (day < 0) ? (day + 7) : day;
1399 };
1400
1401
1402 /**
1403  * Get the first date of this date's month
1404  * @return {Date}
1405  */
1406 Date.prototype.getFirstDateOfMonth = function() {
1407     return new Date(this.getFullYear(), this.getMonth(), 1);
1408 };
1409
1410 /**
1411  * Get the last date of this date's month
1412  * @return {Date}
1413  */
1414 Date.prototype.getLastDateOfMonth = function() {
1415     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1416 };
1417 /**
1418  * Get the number of days in the current month, adjusted for leap year.
1419  * @return {Number} The number of days in the month
1420  */
1421 Date.prototype.getDaysInMonth = function() {
1422     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1423     return Date.daysInMonth[this.getMonth()];
1424 };
1425
1426 /**
1427  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1428  * @return {String} 'st, 'nd', 'rd' or 'th'
1429  */
1430 Date.prototype.getSuffix = function() {
1431     switch (this.getDate()) {
1432         case 1:
1433         case 21:
1434         case 31:
1435             return "st";
1436         case 2:
1437         case 22:
1438             return "nd";
1439         case 3:
1440         case 23:
1441             return "rd";
1442         default:
1443             return "th";
1444     }
1445 };
1446
1447 // private
1448 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1449
1450 /**
1451  * An array of textual month names.
1452  * Override these values for international dates, for example...
1453  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1454  * @type Array
1455  * @static
1456  */
1457 Date.monthNames =
1458    ["January",
1459     "February",
1460     "March",
1461     "April",
1462     "May",
1463     "June",
1464     "July",
1465     "August",
1466     "September",
1467     "October",
1468     "November",
1469     "December"];
1470
1471 /**
1472  * An array of textual day names.
1473  * Override these values for international dates, for example...
1474  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1475  * @type Array
1476  * @static
1477  */
1478 Date.dayNames =
1479    ["Sunday",
1480     "Monday",
1481     "Tuesday",
1482     "Wednesday",
1483     "Thursday",
1484     "Friday",
1485     "Saturday"];
1486
1487 // private
1488 Date.y2kYear = 50;
1489 // private
1490 Date.monthNumbers = {
1491     Jan:0,
1492     Feb:1,
1493     Mar:2,
1494     Apr:3,
1495     May:4,
1496     Jun:5,
1497     Jul:6,
1498     Aug:7,
1499     Sep:8,
1500     Oct:9,
1501     Nov:10,
1502     Dec:11};
1503
1504 /**
1505  * Creates and returns a new Date instance with the exact same date value as the called instance.
1506  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1507  * variable will also be changed.  When the intention is to create a new variable that will not
1508  * modify the original instance, you should create a clone.
1509  *
1510  * Example of correctly cloning a date:
1511  * <pre><code>
1512 //wrong way:
1513 var orig = new Date('10/1/2006');
1514 var copy = orig;
1515 copy.setDate(5);
1516 document.write(orig);  //returns 'Thu Oct 05 2006'!
1517
1518 //correct way:
1519 var orig = new Date('10/1/2006');
1520 var copy = orig.clone();
1521 copy.setDate(5);
1522 document.write(orig);  //returns 'Thu Oct 01 2006'
1523 </code></pre>
1524  * @return {Date} The new Date instance
1525  */
1526 Date.prototype.clone = function() {
1527         return new Date(this.getTime());
1528 };
1529
1530 /**
1531  * Clears any time information from this date
1532  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1533  @return {Date} this or the clone
1534  */
1535 Date.prototype.clearTime = function(clone){
1536     if(clone){
1537         return this.clone().clearTime();
1538     }
1539     this.setHours(0);
1540     this.setMinutes(0);
1541     this.setSeconds(0);
1542     this.setMilliseconds(0);
1543     return this;
1544 };
1545
1546 // private
1547 // safari setMonth is broken
1548 if(Roo.isSafari){
1549     Date.brokenSetMonth = Date.prototype.setMonth;
1550         Date.prototype.setMonth = function(num){
1551                 if(num <= -1){
1552                         var n = Math.ceil(-num);
1553                         var back_year = Math.ceil(n/12);
1554                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1555                         this.setFullYear(this.getFullYear() - back_year);
1556                         return Date.brokenSetMonth.call(this, month);
1557                 } else {
1558                         return Date.brokenSetMonth.apply(this, arguments);
1559                 }
1560         };
1561 }
1562
1563 /** Date interval constant 
1564 * @static 
1565 * @type String */
1566 Date.MILLI = "ms";
1567 /** Date interval constant 
1568 * @static 
1569 * @type String */
1570 Date.SECOND = "s";
1571 /** Date interval constant 
1572 * @static 
1573 * @type String */
1574 Date.MINUTE = "mi";
1575 /** Date interval constant 
1576 * @static 
1577 * @type String */
1578 Date.HOUR = "h";
1579 /** Date interval constant 
1580 * @static 
1581 * @type String */
1582 Date.DAY = "d";
1583 /** Date interval constant 
1584 * @static 
1585 * @type String */
1586 Date.MONTH = "mo";
1587 /** Date interval constant 
1588 * @static 
1589 * @type String */
1590 Date.YEAR = "y";
1591
1592 /**
1593  * Provides a convenient method of performing basic date arithmetic.  This method
1594  * does not modify the Date instance being called - it creates and returns
1595  * a new Date instance containing the resulting date value.
1596  *
1597  * Examples:
1598  * <pre><code>
1599 //Basic usage:
1600 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1601 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1602
1603 //Negative values will subtract correctly:
1604 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1605 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1606
1607 //You can even chain several calls together in one line!
1608 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1609 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1610  </code></pre>
1611  *
1612  * @param {String} interval   A valid date interval enum value
1613  * @param {Number} value      The amount to add to the current date
1614  * @return {Date} The new Date instance
1615  */
1616 Date.prototype.add = function(interval, value){
1617   var d = this.clone();
1618   if (!interval || value === 0) return d;
1619   switch(interval.toLowerCase()){
1620     case Date.MILLI:
1621       d.setMilliseconds(this.getMilliseconds() + value);
1622       break;
1623     case Date.SECOND:
1624       d.setSeconds(this.getSeconds() + value);
1625       break;
1626     case Date.MINUTE:
1627       d.setMinutes(this.getMinutes() + value);
1628       break;
1629     case Date.HOUR:
1630       d.setHours(this.getHours() + value);
1631       break;
1632     case Date.DAY:
1633       d.setDate(this.getDate() + value);
1634       break;
1635     case Date.MONTH:
1636       var day = this.getDate();
1637       if(day > 28){
1638           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1639       }
1640       d.setDate(day);
1641       d.setMonth(this.getMonth() + value);
1642       break;
1643     case Date.YEAR:
1644       d.setFullYear(this.getFullYear() + value);
1645       break;
1646   }
1647   return d;
1648 };/*
1649  * Based on:
1650  * Ext JS Library 1.1.1
1651  * Copyright(c) 2006-2007, Ext JS, LLC.
1652  *
1653  * Originally Released Under LGPL - original licence link has changed is not relivant.
1654  *
1655  * Fork - LGPL
1656  * <script type="text/javascript">
1657  */
1658
1659 Roo.lib.Dom = {
1660     getViewWidth : function(full) {
1661         return full ? this.getDocumentWidth() : this.getViewportWidth();
1662     },
1663
1664     getViewHeight : function(full) {
1665         return full ? this.getDocumentHeight() : this.getViewportHeight();
1666     },
1667
1668     getDocumentHeight: function() {
1669         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1670         return Math.max(scrollHeight, this.getViewportHeight());
1671     },
1672
1673     getDocumentWidth: function() {
1674         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1675         return Math.max(scrollWidth, this.getViewportWidth());
1676     },
1677
1678     getViewportHeight: function() {
1679         var height = self.innerHeight;
1680         var mode = document.compatMode;
1681
1682         if ((mode || Roo.isIE) && !Roo.isOpera) {
1683             height = (mode == "CSS1Compat") ?
1684                      document.documentElement.clientHeight :
1685                      document.body.clientHeight;
1686         }
1687
1688         return height;
1689     },
1690
1691     getViewportWidth: function() {
1692         var width = self.innerWidth;
1693         var mode = document.compatMode;
1694
1695         if (mode || Roo.isIE) {
1696             width = (mode == "CSS1Compat") ?
1697                     document.documentElement.clientWidth :
1698                     document.body.clientWidth;
1699         }
1700         return width;
1701     },
1702
1703     isAncestor : function(p, c) {
1704         p = Roo.getDom(p);
1705         c = Roo.getDom(c);
1706         if (!p || !c) {
1707             return false;
1708         }
1709
1710         if (p.contains && !Roo.isSafari) {
1711             return p.contains(c);
1712         } else if (p.compareDocumentPosition) {
1713             return !!(p.compareDocumentPosition(c) & 16);
1714         } else {
1715             var parent = c.parentNode;
1716             while (parent) {
1717                 if (parent == p) {
1718                     return true;
1719                 }
1720                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1721                     return false;
1722                 }
1723                 parent = parent.parentNode;
1724             }
1725             return false;
1726         }
1727     },
1728
1729     getRegion : function(el) {
1730         return Roo.lib.Region.getRegion(el);
1731     },
1732
1733     getY : function(el) {
1734         return this.getXY(el)[1];
1735     },
1736
1737     getX : function(el) {
1738         return this.getXY(el)[0];
1739     },
1740
1741     getXY : function(el) {
1742         var p, pe, b, scroll, bd = document.body;
1743         el = Roo.getDom(el);
1744         var fly = Roo.lib.AnimBase.fly;
1745         if (el.getBoundingClientRect) {
1746             b = el.getBoundingClientRect();
1747             scroll = fly(document).getScroll();
1748             return [b.left + scroll.left, b.top + scroll.top];
1749         }
1750         var x = 0, y = 0;
1751
1752         p = el;
1753
1754         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1755
1756         while (p) {
1757
1758             x += p.offsetLeft;
1759             y += p.offsetTop;
1760
1761             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1762                 hasAbsolute = true;
1763             }
1764
1765             if (Roo.isGecko) {
1766                 pe = fly(p);
1767
1768                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1769                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1770
1771
1772                 x += bl;
1773                 y += bt;
1774
1775
1776                 if (p != el && pe.getStyle('overflow') != 'visible') {
1777                     x += bl;
1778                     y += bt;
1779                 }
1780             }
1781             p = p.offsetParent;
1782         }
1783
1784         if (Roo.isSafari && hasAbsolute) {
1785             x -= bd.offsetLeft;
1786             y -= bd.offsetTop;
1787         }
1788
1789         if (Roo.isGecko && !hasAbsolute) {
1790             var dbd = fly(bd);
1791             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1792             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1793         }
1794
1795         p = el.parentNode;
1796         while (p && p != bd) {
1797             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1798                 x -= p.scrollLeft;
1799                 y -= p.scrollTop;
1800             }
1801             p = p.parentNode;
1802         }
1803         return [x, y];
1804     },
1805  
1806   
1807
1808
1809     setXY : function(el, xy) {
1810         el = Roo.fly(el, '_setXY');
1811         el.position();
1812         var pts = el.translatePoints(xy);
1813         if (xy[0] !== false) {
1814             el.dom.style.left = pts.left + "px";
1815         }
1816         if (xy[1] !== false) {
1817             el.dom.style.top = pts.top + "px";
1818         }
1819     },
1820
1821     setX : function(el, x) {
1822         this.setXY(el, [x, false]);
1823     },
1824
1825     setY : function(el, y) {
1826         this.setXY(el, [false, y]);
1827     }
1828 };
1829 /*
1830  * Portions of this file are based on pieces of Yahoo User Interface Library
1831  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1832  * YUI licensed under the BSD License:
1833  * http://developer.yahoo.net/yui/license.txt
1834  * <script type="text/javascript">
1835  *
1836  */
1837
1838 Roo.lib.Event = function() {
1839     var loadComplete = false;
1840     var listeners = [];
1841     var unloadListeners = [];
1842     var retryCount = 0;
1843     var onAvailStack = [];
1844     var counter = 0;
1845     var lastError = null;
1846
1847     return {
1848         POLL_RETRYS: 200,
1849         POLL_INTERVAL: 20,
1850         EL: 0,
1851         TYPE: 1,
1852         FN: 2,
1853         WFN: 3,
1854         OBJ: 3,
1855         ADJ_SCOPE: 4,
1856         _interval: null,
1857
1858         startInterval: function() {
1859             if (!this._interval) {
1860                 var self = this;
1861                 var callback = function() {
1862                     self._tryPreloadAttach();
1863                 };
1864                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1865
1866             }
1867         },
1868
1869         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1870             onAvailStack.push({ id:         p_id,
1871                 fn:         p_fn,
1872                 obj:        p_obj,
1873                 override:   p_override,
1874                 checkReady: false    });
1875
1876             retryCount = this.POLL_RETRYS;
1877             this.startInterval();
1878         },
1879
1880
1881         addListener: function(el, eventName, fn) {
1882             el = Roo.getDom(el);
1883             if (!el || !fn) {
1884                 return false;
1885             }
1886
1887             if ("unload" == eventName) {
1888                 unloadListeners[unloadListeners.length] =
1889                 [el, eventName, fn];
1890                 return true;
1891             }
1892
1893             var wrappedFn = function(e) {
1894                 return fn(Roo.lib.Event.getEvent(e));
1895             };
1896
1897             var li = [el, eventName, fn, wrappedFn];
1898
1899             var index = listeners.length;
1900             listeners[index] = li;
1901
1902             this.doAdd(el, eventName, wrappedFn, false);
1903             return true;
1904
1905         },
1906
1907
1908         removeListener: function(el, eventName, fn) {
1909             var i, len;
1910
1911             el = Roo.getDom(el);
1912
1913             if(!fn) {
1914                 return this.purgeElement(el, false, eventName);
1915             }
1916
1917
1918             if ("unload" == eventName) {
1919
1920                 for (i = 0,len = unloadListeners.length; i < len; i++) {
1921                     var li = unloadListeners[i];
1922                     if (li &&
1923                         li[0] == el &&
1924                         li[1] == eventName &&
1925                         li[2] == fn) {
1926                         unloadListeners.splice(i, 1);
1927                         return true;
1928                     }
1929                 }
1930
1931                 return false;
1932             }
1933
1934             var cacheItem = null;
1935
1936
1937             var index = arguments[3];
1938
1939             if ("undefined" == typeof index) {
1940                 index = this._getCacheIndex(el, eventName, fn);
1941             }
1942
1943             if (index >= 0) {
1944                 cacheItem = listeners[index];
1945             }
1946
1947             if (!el || !cacheItem) {
1948                 return false;
1949             }
1950
1951             this.doRemove(el, eventName, cacheItem[this.WFN], false);
1952
1953             delete listeners[index][this.WFN];
1954             delete listeners[index][this.FN];
1955             listeners.splice(index, 1);
1956
1957             return true;
1958
1959         },
1960
1961
1962         getTarget: function(ev, resolveTextNode) {
1963             ev = ev.browserEvent || ev;
1964             var t = ev.target || ev.srcElement;
1965             return this.resolveTextNode(t);
1966         },
1967
1968
1969         resolveTextNode: function(node) {
1970             if (Roo.isSafari && node && 3 == node.nodeType) {
1971                 return node.parentNode;
1972             } else {
1973                 return node;
1974             }
1975         },
1976
1977
1978         getPageX: function(ev) {
1979             ev = ev.browserEvent || ev;
1980             var x = ev.pageX;
1981             if (!x && 0 !== x) {
1982                 x = ev.clientX || 0;
1983
1984                 if (Roo.isIE) {
1985                     x += this.getScroll()[1];
1986                 }
1987             }
1988
1989             return x;
1990         },
1991
1992
1993         getPageY: function(ev) {
1994             ev = ev.browserEvent || ev;
1995             var y = ev.pageY;
1996             if (!y && 0 !== y) {
1997                 y = ev.clientY || 0;
1998
1999                 if (Roo.isIE) {
2000                     y += this.getScroll()[0];
2001                 }
2002             }
2003
2004
2005             return y;
2006         },
2007
2008
2009         getXY: function(ev) {
2010             ev = ev.browserEvent || ev;
2011             return [this.getPageX(ev), this.getPageY(ev)];
2012         },
2013
2014
2015         getRelatedTarget: function(ev) {
2016             ev = ev.browserEvent || ev;
2017             var t = ev.relatedTarget;
2018             if (!t) {
2019                 if (ev.type == "mouseout") {
2020                     t = ev.toElement;
2021                 } else if (ev.type == "mouseover") {
2022                     t = ev.fromElement;
2023                 }
2024             }
2025
2026             return this.resolveTextNode(t);
2027         },
2028
2029
2030         getTime: function(ev) {
2031             ev = ev.browserEvent || ev;
2032             if (!ev.time) {
2033                 var t = new Date().getTime();
2034                 try {
2035                     ev.time = t;
2036                 } catch(ex) {
2037                     this.lastError = ex;
2038                     return t;
2039                 }
2040             }
2041
2042             return ev.time;
2043         },
2044
2045
2046         stopEvent: function(ev) {
2047             this.stopPropagation(ev);
2048             this.preventDefault(ev);
2049         },
2050
2051
2052         stopPropagation: function(ev) {
2053             ev = ev.browserEvent || ev;
2054             if (ev.stopPropagation) {
2055                 ev.stopPropagation();
2056             } else {
2057                 ev.cancelBubble = true;
2058             }
2059         },
2060
2061
2062         preventDefault: function(ev) {
2063             ev = ev.browserEvent || ev;
2064             if(ev.preventDefault) {
2065                 ev.preventDefault();
2066             } else {
2067                 ev.returnValue = false;
2068             }
2069         },
2070
2071
2072         getEvent: function(e) {
2073             var ev = e || window.event;
2074             if (!ev) {
2075                 var c = this.getEvent.caller;
2076                 while (c) {
2077                     ev = c.arguments[0];
2078                     if (ev && Event == ev.constructor) {
2079                         break;
2080                     }
2081                     c = c.caller;
2082                 }
2083             }
2084             return ev;
2085         },
2086
2087
2088         getCharCode: function(ev) {
2089             ev = ev.browserEvent || ev;
2090             return ev.charCode || ev.keyCode || 0;
2091         },
2092
2093
2094         _getCacheIndex: function(el, eventName, fn) {
2095             for (var i = 0,len = listeners.length; i < len; ++i) {
2096                 var li = listeners[i];
2097                 if (li &&
2098                     li[this.FN] == fn &&
2099                     li[this.EL] == el &&
2100                     li[this.TYPE] == eventName) {
2101                     return i;
2102                 }
2103             }
2104
2105             return -1;
2106         },
2107
2108
2109         elCache: {},
2110
2111
2112         getEl: function(id) {
2113             return document.getElementById(id);
2114         },
2115
2116
2117         clearCache: function() {
2118         },
2119
2120
2121         _load: function(e) {
2122             loadComplete = true;
2123             var EU = Roo.lib.Event;
2124
2125
2126             if (Roo.isIE) {
2127                 EU.doRemove(window, "load", EU._load);
2128             }
2129         },
2130
2131
2132         _tryPreloadAttach: function() {
2133
2134             if (this.locked) {
2135                 return false;
2136             }
2137
2138             this.locked = true;
2139
2140
2141             var tryAgain = !loadComplete;
2142             if (!tryAgain) {
2143                 tryAgain = (retryCount > 0);
2144             }
2145
2146
2147             var notAvail = [];
2148             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2149                 var item = onAvailStack[i];
2150                 if (item) {
2151                     var el = this.getEl(item.id);
2152
2153                     if (el) {
2154                         if (!item.checkReady ||
2155                             loadComplete ||
2156                             el.nextSibling ||
2157                             (document && document.body)) {
2158
2159                             var scope = el;
2160                             if (item.override) {
2161                                 if (item.override === true) {
2162                                     scope = item.obj;
2163                                 } else {
2164                                     scope = item.override;
2165                                 }
2166                             }
2167                             item.fn.call(scope, item.obj);
2168                             onAvailStack[i] = null;
2169                         }
2170                     } else {
2171                         notAvail.push(item);
2172                     }
2173                 }
2174             }
2175
2176             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2177
2178             if (tryAgain) {
2179
2180                 this.startInterval();
2181             } else {
2182                 clearInterval(this._interval);
2183                 this._interval = null;
2184             }
2185
2186             this.locked = false;
2187
2188             return true;
2189
2190         },
2191
2192
2193         purgeElement: function(el, recurse, eventName) {
2194             var elListeners = this.getListeners(el, eventName);
2195             if (elListeners) {
2196                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2197                     var l = elListeners[i];
2198                     this.removeListener(el, l.type, l.fn);
2199                 }
2200             }
2201
2202             if (recurse && el && el.childNodes) {
2203                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2204                     this.purgeElement(el.childNodes[i], recurse, eventName);
2205                 }
2206             }
2207         },
2208
2209
2210         getListeners: function(el, eventName) {
2211             var results = [], searchLists;
2212             if (!eventName) {
2213                 searchLists = [listeners, unloadListeners];
2214             } else if (eventName == "unload") {
2215                 searchLists = [unloadListeners];
2216             } else {
2217                 searchLists = [listeners];
2218             }
2219
2220             for (var j = 0; j < searchLists.length; ++j) {
2221                 var searchList = searchLists[j];
2222                 if (searchList && searchList.length > 0) {
2223                     for (var i = 0,len = searchList.length; i < len; ++i) {
2224                         var l = searchList[i];
2225                         if (l && l[this.EL] === el &&
2226                             (!eventName || eventName === l[this.TYPE])) {
2227                             results.push({
2228                                 type:   l[this.TYPE],
2229                                 fn:     l[this.FN],
2230                                 obj:    l[this.OBJ],
2231                                 adjust: l[this.ADJ_SCOPE],
2232                                 index:  i
2233                             });
2234                         }
2235                     }
2236                 }
2237             }
2238
2239             return (results.length) ? results : null;
2240         },
2241
2242
2243         _unload: function(e) {
2244
2245             var EU = Roo.lib.Event, i, j, l, len, index;
2246
2247             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2248                 l = unloadListeners[i];
2249                 if (l) {
2250                     var scope = window;
2251                     if (l[EU.ADJ_SCOPE]) {
2252                         if (l[EU.ADJ_SCOPE] === true) {
2253                             scope = l[EU.OBJ];
2254                         } else {
2255                             scope = l[EU.ADJ_SCOPE];
2256                         }
2257                     }
2258                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2259                     unloadListeners[i] = null;
2260                     l = null;
2261                     scope = null;
2262                 }
2263             }
2264
2265             unloadListeners = null;
2266
2267             if (listeners && listeners.length > 0) {
2268                 j = listeners.length;
2269                 while (j) {
2270                     index = j - 1;
2271                     l = listeners[index];
2272                     if (l) {
2273                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2274                                 l[EU.FN], index);
2275                     }
2276                     j = j - 1;
2277                 }
2278                 l = null;
2279
2280                 EU.clearCache();
2281             }
2282
2283             EU.doRemove(window, "unload", EU._unload);
2284
2285         },
2286
2287
2288         getScroll: function() {
2289             var dd = document.documentElement, db = document.body;
2290             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2291                 return [dd.scrollTop, dd.scrollLeft];
2292             } else if (db) {
2293                 return [db.scrollTop, db.scrollLeft];
2294             } else {
2295                 return [0, 0];
2296             }
2297         },
2298
2299
2300         doAdd: function () {
2301             if (window.addEventListener) {
2302                 return function(el, eventName, fn, capture) {
2303                     el.addEventListener(eventName, fn, (capture));
2304                 };
2305             } else if (window.attachEvent) {
2306                 return function(el, eventName, fn, capture) {
2307                     el.attachEvent("on" + eventName, fn);
2308                 };
2309             } else {
2310                 return function() {
2311                 };
2312             }
2313         }(),
2314
2315
2316         doRemove: function() {
2317             if (window.removeEventListener) {
2318                 return function (el, eventName, fn, capture) {
2319                     el.removeEventListener(eventName, fn, (capture));
2320                 };
2321             } else if (window.detachEvent) {
2322                 return function (el, eventName, fn) {
2323                     el.detachEvent("on" + eventName, fn);
2324                 };
2325             } else {
2326                 return function() {
2327                 };
2328             }
2329         }()
2330     };
2331     
2332 }();
2333 (function() {     
2334    
2335     var E = Roo.lib.Event;
2336     E.on = E.addListener;
2337     E.un = E.removeListener;
2338
2339     if (document && document.body) {
2340         E._load();
2341     } else {
2342         E.doAdd(window, "load", E._load);
2343     }
2344     E.doAdd(window, "unload", E._unload);
2345     E._tryPreloadAttach();
2346 })();
2347
2348 /*
2349  * Portions of this file are based on pieces of Yahoo User Interface Library
2350  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2351  * YUI licensed under the BSD License:
2352  * http://developer.yahoo.net/yui/license.txt
2353  * <script type="text/javascript">
2354  *
2355  */
2356
2357 (function() {
2358     
2359     Roo.lib.Ajax = {
2360         request : function(method, uri, cb, data, options) {
2361             if(options){
2362                 var hs = options.headers;
2363                 if(hs){
2364                     for(var h in hs){
2365                         if(hs.hasOwnProperty(h)){
2366                             this.initHeader(h, hs[h], false);
2367                         }
2368                     }
2369                 }
2370                 if(options.xmlData){
2371                     this.initHeader('Content-Type', 'text/xml', false);
2372                     method = 'POST';
2373                     data = options.xmlData;
2374                 }
2375             }
2376
2377             return this.asyncRequest(method, uri, cb, data);
2378         },
2379
2380         serializeForm : function(form) {
2381             if(typeof form == 'string') {
2382                 form = (document.getElementById(form) || document.forms[form]);
2383             }
2384
2385             var el, name, val, disabled, data = '', hasSubmit = false;
2386             for (var i = 0; i < form.elements.length; i++) {
2387                 el = form.elements[i];
2388                 disabled = form.elements[i].disabled;
2389                 name = form.elements[i].name;
2390                 val = form.elements[i].value;
2391
2392                 if (!disabled && name){
2393                     switch (el.type)
2394                             {
2395                         case 'select-one':
2396                         case 'select-multiple':
2397                             for (var j = 0; j < el.options.length; j++) {
2398                                 if (el.options[j].selected) {
2399                                     if (Roo.isIE) {
2400                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2401                                     }
2402                                     else {
2403                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2404                                     }
2405                                 }
2406                             }
2407                             break;
2408                         case 'radio':
2409                         case 'checkbox':
2410                             if (el.checked) {
2411                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2412                             }
2413                             break;
2414                         case 'file':
2415
2416                         case undefined:
2417
2418                         case 'reset':
2419
2420                         case 'button':
2421
2422                             break;
2423                         case 'submit':
2424                             if(hasSubmit == false) {
2425                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2426                                 hasSubmit = true;
2427                             }
2428                             break;
2429                         default:
2430                             data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2431                             break;
2432                     }
2433                 }
2434             }
2435             data = data.substr(0, data.length - 1);
2436             return data;
2437         },
2438
2439         headers:{},
2440
2441         hasHeaders:false,
2442
2443         useDefaultHeader:true,
2444
2445         defaultPostHeader:'application/x-www-form-urlencoded',
2446
2447         useDefaultXhrHeader:true,
2448
2449         defaultXhrHeader:'XMLHttpRequest',
2450
2451         hasDefaultHeaders:true,
2452
2453         defaultHeaders:{},
2454
2455         poll:{},
2456
2457         timeout:{},
2458
2459         pollInterval:50,
2460
2461         transactionId:0,
2462
2463         setProgId:function(id)
2464         {
2465             this.activeX.unshift(id);
2466         },
2467
2468         setDefaultPostHeader:function(b)
2469         {
2470             this.useDefaultHeader = b;
2471         },
2472
2473         setDefaultXhrHeader:function(b)
2474         {
2475             this.useDefaultXhrHeader = b;
2476         },
2477
2478         setPollingInterval:function(i)
2479         {
2480             if (typeof i == 'number' && isFinite(i)) {
2481                 this.pollInterval = i;
2482             }
2483         },
2484
2485         createXhrObject:function(transactionId)
2486         {
2487             var obj,http;
2488             try
2489             {
2490
2491                 http = new XMLHttpRequest();
2492
2493                 obj = { conn:http, tId:transactionId };
2494             }
2495             catch(e)
2496             {
2497                 for (var i = 0; i < this.activeX.length; ++i) {
2498                     try
2499                     {
2500
2501                         http = new ActiveXObject(this.activeX[i]);
2502
2503                         obj = { conn:http, tId:transactionId };
2504                         break;
2505                     }
2506                     catch(e) {
2507                     }
2508                 }
2509             }
2510             finally
2511             {
2512                 return obj;
2513             }
2514         },
2515
2516         getConnectionObject:function()
2517         {
2518             var o;
2519             var tId = this.transactionId;
2520
2521             try
2522             {
2523                 o = this.createXhrObject(tId);
2524                 if (o) {
2525                     this.transactionId++;
2526                 }
2527             }
2528             catch(e) {
2529             }
2530             finally
2531             {
2532                 return o;
2533             }
2534         },
2535
2536         asyncRequest:function(method, uri, callback, postData)
2537         {
2538             var o = this.getConnectionObject();
2539
2540             if (!o) {
2541                 return null;
2542             }
2543             else {
2544                 o.conn.open(method, uri, true);
2545
2546                 if (this.useDefaultXhrHeader) {
2547                     if (!this.defaultHeaders['X-Requested-With']) {
2548                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2549                     }
2550                 }
2551
2552                 if(postData && this.useDefaultHeader){
2553                     this.initHeader('Content-Type', this.defaultPostHeader);
2554                 }
2555
2556                  if (this.hasDefaultHeaders || this.hasHeaders) {
2557                     this.setHeader(o);
2558                 }
2559
2560                 this.handleReadyState(o, callback);
2561                 o.conn.send(postData || null);
2562
2563                 return o;
2564             }
2565         },
2566
2567         handleReadyState:function(o, callback)
2568         {
2569             var oConn = this;
2570
2571             if (callback && callback.timeout) {
2572                 this.timeout[o.tId] = window.setTimeout(function() {
2573                     oConn.abort(o, callback, true);
2574                 }, callback.timeout);
2575             }
2576
2577             this.poll[o.tId] = window.setInterval(
2578                     function() {
2579                         if (o.conn && o.conn.readyState == 4) {
2580                             window.clearInterval(oConn.poll[o.tId]);
2581                             delete oConn.poll[o.tId];
2582
2583                             if(callback && callback.timeout) {
2584                                 window.clearTimeout(oConn.timeout[o.tId]);
2585                                 delete oConn.timeout[o.tId];
2586                             }
2587
2588                             oConn.handleTransactionResponse(o, callback);
2589                         }
2590                     }
2591                     , this.pollInterval);
2592         },
2593
2594         handleTransactionResponse:function(o, callback, isAbort)
2595         {
2596
2597             if (!callback) {
2598                 this.releaseObject(o);
2599                 return;
2600             }
2601
2602             var httpStatus, responseObject;
2603
2604             try
2605             {
2606                 if (o.conn.status !== undefined && o.conn.status != 0) {
2607                     httpStatus = o.conn.status;
2608                 }
2609                 else {
2610                     httpStatus = 13030;
2611                 }
2612             }
2613             catch(e) {
2614
2615
2616                 httpStatus = 13030;
2617             }
2618
2619             if (httpStatus >= 200 && httpStatus < 300) {
2620                 responseObject = this.createResponseObject(o, callback.argument);
2621                 if (callback.success) {
2622                     if (!callback.scope) {
2623                         callback.success(responseObject);
2624                     }
2625                     else {
2626
2627
2628                         callback.success.apply(callback.scope, [responseObject]);
2629                     }
2630                 }
2631             }
2632             else {
2633                 switch (httpStatus) {
2634
2635                     case 12002:
2636                     case 12029:
2637                     case 12030:
2638                     case 12031:
2639                     case 12152:
2640                     case 13030:
2641                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2642                         if (callback.failure) {
2643                             if (!callback.scope) {
2644                                 callback.failure(responseObject);
2645                             }
2646                             else {
2647                                 callback.failure.apply(callback.scope, [responseObject]);
2648                             }
2649                         }
2650                         break;
2651                     default:
2652                         responseObject = this.createResponseObject(o, callback.argument);
2653                         if (callback.failure) {
2654                             if (!callback.scope) {
2655                                 callback.failure(responseObject);
2656                             }
2657                             else {
2658                                 callback.failure.apply(callback.scope, [responseObject]);
2659                             }
2660                         }
2661                 }
2662             }
2663
2664             this.releaseObject(o);
2665             responseObject = null;
2666         },
2667
2668         createResponseObject:function(o, callbackArg)
2669         {
2670             var obj = {};
2671             var headerObj = {};
2672
2673             try
2674             {
2675                 var headerStr = o.conn.getAllResponseHeaders();
2676                 var header = headerStr.split('\n');
2677                 for (var i = 0; i < header.length; i++) {
2678                     var delimitPos = header[i].indexOf(':');
2679                     if (delimitPos != -1) {
2680                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2681                     }
2682                 }
2683             }
2684             catch(e) {
2685             }
2686
2687             obj.tId = o.tId;
2688             obj.status = o.conn.status;
2689             obj.statusText = o.conn.statusText;
2690             obj.getResponseHeader = headerObj;
2691             obj.getAllResponseHeaders = headerStr;
2692             obj.responseText = o.conn.responseText;
2693             obj.responseXML = o.conn.responseXML;
2694
2695             if (typeof callbackArg !== undefined) {
2696                 obj.argument = callbackArg;
2697             }
2698
2699             return obj;
2700         },
2701
2702         createExceptionObject:function(tId, callbackArg, isAbort)
2703         {
2704             var COMM_CODE = 0;
2705             var COMM_ERROR = 'communication failure';
2706             var ABORT_CODE = -1;
2707             var ABORT_ERROR = 'transaction aborted';
2708
2709             var obj = {};
2710
2711             obj.tId = tId;
2712             if (isAbort) {
2713                 obj.status = ABORT_CODE;
2714                 obj.statusText = ABORT_ERROR;
2715             }
2716             else {
2717                 obj.status = COMM_CODE;
2718                 obj.statusText = COMM_ERROR;
2719             }
2720
2721             if (callbackArg) {
2722                 obj.argument = callbackArg;
2723             }
2724
2725             return obj;
2726         },
2727
2728         initHeader:function(label, value, isDefault)
2729         {
2730             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2731
2732             if (headerObj[label] === undefined) {
2733                 headerObj[label] = value;
2734             }
2735             else {
2736
2737
2738                 headerObj[label] = value + "," + headerObj[label];
2739             }
2740
2741             if (isDefault) {
2742                 this.hasDefaultHeaders = true;
2743             }
2744             else {
2745                 this.hasHeaders = true;
2746             }
2747         },
2748
2749
2750         setHeader:function(o)
2751         {
2752             if (this.hasDefaultHeaders) {
2753                 for (var prop in this.defaultHeaders) {
2754                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2755                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2756                     }
2757                 }
2758             }
2759
2760             if (this.hasHeaders) {
2761                 for (var prop in this.headers) {
2762                     if (this.headers.hasOwnProperty(prop)) {
2763                         o.conn.setRequestHeader(prop, this.headers[prop]);
2764                     }
2765                 }
2766                 this.headers = {};
2767                 this.hasHeaders = false;
2768             }
2769         },
2770
2771         resetDefaultHeaders:function() {
2772             delete this.defaultHeaders;
2773             this.defaultHeaders = {};
2774             this.hasDefaultHeaders = false;
2775         },
2776
2777         abort:function(o, callback, isTimeout)
2778         {
2779             if(this.isCallInProgress(o)) {
2780                 o.conn.abort();
2781                 window.clearInterval(this.poll[o.tId]);
2782                 delete this.poll[o.tId];
2783                 if (isTimeout) {
2784                     delete this.timeout[o.tId];
2785                 }
2786
2787                 this.handleTransactionResponse(o, callback, true);
2788
2789                 return true;
2790             }
2791             else {
2792                 return false;
2793             }
2794         },
2795
2796
2797         isCallInProgress:function(o)
2798         {
2799             if (o && o.conn) {
2800                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2801             }
2802             else {
2803
2804                 return false;
2805             }
2806         },
2807
2808
2809         releaseObject:function(o)
2810         {
2811
2812             o.conn = null;
2813
2814             o = null;
2815         },
2816
2817         activeX:[
2818         'MSXML2.XMLHTTP.3.0',
2819         'MSXML2.XMLHTTP',
2820         'Microsoft.XMLHTTP'
2821         ]
2822
2823
2824     };
2825 })();/*
2826  * Portions of this file are based on pieces of Yahoo User Interface Library
2827  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2828  * YUI licensed under the BSD License:
2829  * http://developer.yahoo.net/yui/license.txt
2830  * <script type="text/javascript">
2831  *
2832  */
2833
2834 Roo.lib.Region = function(t, r, b, l) {
2835     this.top = t;
2836     this[1] = t;
2837     this.right = r;
2838     this.bottom = b;
2839     this.left = l;
2840     this[0] = l;
2841 };
2842
2843
2844 Roo.lib.Region.prototype = {
2845     contains : function(region) {
2846         return ( region.left >= this.left &&
2847                  region.right <= this.right &&
2848                  region.top >= this.top &&
2849                  region.bottom <= this.bottom    );
2850
2851     },
2852
2853     getArea : function() {
2854         return ( (this.bottom - this.top) * (this.right - this.left) );
2855     },
2856
2857     intersect : function(region) {
2858         var t = Math.max(this.top, region.top);
2859         var r = Math.min(this.right, region.right);
2860         var b = Math.min(this.bottom, region.bottom);
2861         var l = Math.max(this.left, region.left);
2862
2863         if (b >= t && r >= l) {
2864             return new Roo.lib.Region(t, r, b, l);
2865         } else {
2866             return null;
2867         }
2868     },
2869     union : function(region) {
2870         var t = Math.min(this.top, region.top);
2871         var r = Math.max(this.right, region.right);
2872         var b = Math.max(this.bottom, region.bottom);
2873         var l = Math.min(this.left, region.left);
2874
2875         return new Roo.lib.Region(t, r, b, l);
2876     },
2877
2878     adjust : function(t, l, b, r) {
2879         this.top += t;
2880         this.left += l;
2881         this.right += r;
2882         this.bottom += b;
2883         return this;
2884     }
2885 };
2886
2887 Roo.lib.Region.getRegion = function(el) {
2888     var p = Roo.lib.Dom.getXY(el);
2889
2890     var t = p[1];
2891     var r = p[0] + el.offsetWidth;
2892     var b = p[1] + el.offsetHeight;
2893     var l = p[0];
2894
2895     return new Roo.lib.Region(t, r, b, l);
2896 };
2897 /*
2898  * Portions of this file are based on pieces of Yahoo User Interface Library
2899  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2900  * YUI licensed under the BSD License:
2901  * http://developer.yahoo.net/yui/license.txt
2902  * <script type="text/javascript">
2903  *
2904  */
2905 //@@dep Roo.lib.Region
2906
2907
2908 Roo.lib.Point = function(x, y) {
2909     if (x instanceof Array) {
2910         y = x[1];
2911         x = x[0];
2912     }
2913     this.x = this.right = this.left = this[0] = x;
2914     this.y = this.top = this.bottom = this[1] = y;
2915 };
2916
2917 Roo.lib.Point.prototype = new Roo.lib.Region();
2918 /*
2919  * Portions of this file are based on pieces of Yahoo User Interface Library
2920  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2921  * YUI licensed under the BSD License:
2922  * http://developer.yahoo.net/yui/license.txt
2923  * <script type="text/javascript">
2924  *
2925  */
2926  
2927 (function() {   
2928
2929     Roo.lib.Anim = {
2930         scroll : function(el, args, duration, easing, cb, scope) {
2931             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2932         },
2933
2934         motion : function(el, args, duration, easing, cb, scope) {
2935             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2936         },
2937
2938         color : function(el, args, duration, easing, cb, scope) {
2939             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2940         },
2941
2942         run : function(el, args, duration, easing, cb, scope, type) {
2943             type = type || Roo.lib.AnimBase;
2944             if (typeof easing == "string") {
2945                 easing = Roo.lib.Easing[easing];
2946             }
2947             var anim = new type(el, args, duration, easing);
2948             anim.animateX(function() {
2949                 Roo.callback(cb, scope);
2950             });
2951             return anim;
2952         }
2953     };
2954 })();/*
2955  * Portions of this file are based on pieces of Yahoo User Interface Library
2956  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2957  * YUI licensed under the BSD License:
2958  * http://developer.yahoo.net/yui/license.txt
2959  * <script type="text/javascript">
2960  *
2961  */
2962
2963 (function() {    
2964     var libFlyweight;
2965     
2966     function fly(el) {
2967         if (!libFlyweight) {
2968             libFlyweight = new Roo.Element.Flyweight();
2969         }
2970         libFlyweight.dom = el;
2971         return libFlyweight;
2972     }
2973
2974     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2975     
2976    
2977     
2978     Roo.lib.AnimBase = function(el, attributes, duration, method) {
2979         if (el) {
2980             this.init(el, attributes, duration, method);
2981         }
2982     };
2983
2984     Roo.lib.AnimBase.fly = fly;
2985     
2986     
2987     
2988     Roo.lib.AnimBase.prototype = {
2989
2990         toString: function() {
2991             var el = this.getEl();
2992             var id = el.id || el.tagName;
2993             return ("Anim " + id);
2994         },
2995
2996         patterns: {
2997             noNegatives:        /width|height|opacity|padding/i,
2998             offsetAttribute:  /^((width|height)|(top|left))$/,
2999             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3000             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3001         },
3002
3003
3004         doMethod: function(attr, start, end) {
3005             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3006         },
3007
3008
3009         setAttribute: function(attr, val, unit) {
3010             if (this.patterns.noNegatives.test(attr)) {
3011                 val = (val > 0) ? val : 0;
3012             }
3013
3014             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3015         },
3016
3017
3018         getAttribute: function(attr) {
3019             var el = this.getEl();
3020             var val = fly(el).getStyle(attr);
3021
3022             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3023                 return parseFloat(val);
3024             }
3025
3026             var a = this.patterns.offsetAttribute.exec(attr) || [];
3027             var pos = !!( a[3] );
3028             var box = !!( a[2] );
3029
3030
3031             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3032                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3033             } else {
3034                 val = 0;
3035             }
3036
3037             return val;
3038         },
3039
3040
3041         getDefaultUnit: function(attr) {
3042             if (this.patterns.defaultUnit.test(attr)) {
3043                 return 'px';
3044             }
3045
3046             return '';
3047         },
3048
3049         animateX : function(callback, scope) {
3050             var f = function() {
3051                 this.onComplete.removeListener(f);
3052                 if (typeof callback == "function") {
3053                     callback.call(scope || this, this);
3054                 }
3055             };
3056             this.onComplete.addListener(f, this);
3057             this.animate();
3058         },
3059
3060
3061         setRuntimeAttribute: function(attr) {
3062             var start;
3063             var end;
3064             var attributes = this.attributes;
3065
3066             this.runtimeAttributes[attr] = {};
3067
3068             var isset = function(prop) {
3069                 return (typeof prop !== 'undefined');
3070             };
3071
3072             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3073                 return false;
3074             }
3075
3076             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3077
3078
3079             if (isset(attributes[attr]['to'])) {
3080                 end = attributes[attr]['to'];
3081             } else if (isset(attributes[attr]['by'])) {
3082                 if (start.constructor == Array) {
3083                     end = [];
3084                     for (var i = 0, len = start.length; i < len; ++i) {
3085                         end[i] = start[i] + attributes[attr]['by'][i];
3086                     }
3087                 } else {
3088                     end = start + attributes[attr]['by'];
3089                 }
3090             }
3091
3092             this.runtimeAttributes[attr].start = start;
3093             this.runtimeAttributes[attr].end = end;
3094
3095
3096             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3097         },
3098
3099
3100         init: function(el, attributes, duration, method) {
3101
3102             var isAnimated = false;
3103
3104
3105             var startTime = null;
3106
3107
3108             var actualFrames = 0;
3109
3110
3111             el = Roo.getDom(el);
3112
3113
3114             this.attributes = attributes || {};
3115
3116
3117             this.duration = duration || 1;
3118
3119
3120             this.method = method || Roo.lib.Easing.easeNone;
3121
3122
3123             this.useSeconds = true;
3124
3125
3126             this.currentFrame = 0;
3127
3128
3129             this.totalFrames = Roo.lib.AnimMgr.fps;
3130
3131
3132             this.getEl = function() {
3133                 return el;
3134             };
3135
3136
3137             this.isAnimated = function() {
3138                 return isAnimated;
3139             };
3140
3141
3142             this.getStartTime = function() {
3143                 return startTime;
3144             };
3145
3146             this.runtimeAttributes = {};
3147
3148
3149             this.animate = function() {
3150                 if (this.isAnimated()) {
3151                     return false;
3152                 }
3153
3154                 this.currentFrame = 0;
3155
3156                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3157
3158                 Roo.lib.AnimMgr.registerElement(this);
3159             };
3160
3161
3162             this.stop = function(finish) {
3163                 if (finish) {
3164                     this.currentFrame = this.totalFrames;
3165                     this._onTween.fire();
3166                 }
3167                 Roo.lib.AnimMgr.stop(this);
3168             };
3169
3170             var onStart = function() {
3171                 this.onStart.fire();
3172
3173                 this.runtimeAttributes = {};
3174                 for (var attr in this.attributes) {
3175                     this.setRuntimeAttribute(attr);
3176                 }
3177
3178                 isAnimated = true;
3179                 actualFrames = 0;
3180                 startTime = new Date();
3181             };
3182
3183
3184             var onTween = function() {
3185                 var data = {
3186                     duration: new Date() - this.getStartTime(),
3187                     currentFrame: this.currentFrame
3188                 };
3189
3190                 data.toString = function() {
3191                     return (
3192                             'duration: ' + data.duration +
3193                             ', currentFrame: ' + data.currentFrame
3194                             );
3195                 };
3196
3197                 this.onTween.fire(data);
3198
3199                 var runtimeAttributes = this.runtimeAttributes;
3200
3201                 for (var attr in runtimeAttributes) {
3202                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3203                 }
3204
3205                 actualFrames += 1;
3206             };
3207
3208             var onComplete = function() {
3209                 var actual_duration = (new Date() - startTime) / 1000 ;
3210
3211                 var data = {
3212                     duration: actual_duration,
3213                     frames: actualFrames,
3214                     fps: actualFrames / actual_duration
3215                 };
3216
3217                 data.toString = function() {
3218                     return (
3219                             'duration: ' + data.duration +
3220                             ', frames: ' + data.frames +
3221                             ', fps: ' + data.fps
3222                             );
3223                 };
3224
3225                 isAnimated = false;
3226                 actualFrames = 0;
3227                 this.onComplete.fire(data);
3228             };
3229
3230
3231             this._onStart = new Roo.util.Event(this);
3232             this.onStart = new Roo.util.Event(this);
3233             this.onTween = new Roo.util.Event(this);
3234             this._onTween = new Roo.util.Event(this);
3235             this.onComplete = new Roo.util.Event(this);
3236             this._onComplete = new Roo.util.Event(this);
3237             this._onStart.addListener(onStart);
3238             this._onTween.addListener(onTween);
3239             this._onComplete.addListener(onComplete);
3240         }
3241     };
3242 })();
3243 /*
3244  * Portions of this file are based on pieces of Yahoo User Interface Library
3245  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3246  * YUI licensed under the BSD License:
3247  * http://developer.yahoo.net/yui/license.txt
3248  * <script type="text/javascript">
3249  *
3250  */
3251
3252 Roo.lib.AnimMgr = new function() {
3253
3254         var thread = null;
3255
3256
3257         var queue = [];
3258
3259
3260         var tweenCount = 0;
3261
3262
3263         this.fps = 1000;
3264
3265
3266         this.delay = 1;
3267
3268
3269         this.registerElement = function(tween) {
3270             queue[queue.length] = tween;
3271             tweenCount += 1;
3272             tween._onStart.fire();
3273             this.start();
3274         };
3275
3276
3277         this.unRegister = function(tween, index) {
3278             tween._onComplete.fire();
3279             index = index || getIndex(tween);
3280             if (index != -1) {
3281                 queue.splice(index, 1);
3282             }
3283
3284             tweenCount -= 1;
3285             if (tweenCount <= 0) {
3286                 this.stop();
3287             }
3288         };
3289
3290
3291         this.start = function() {
3292             if (thread === null) {
3293                 thread = setInterval(this.run, this.delay);
3294             }
3295         };
3296
3297
3298         this.stop = function(tween) {
3299             if (!tween) {
3300                 clearInterval(thread);
3301
3302                 for (var i = 0, len = queue.length; i < len; ++i) {
3303                     if (queue[0].isAnimated()) {
3304                         this.unRegister(queue[0], 0);
3305                     }
3306                 }
3307
3308                 queue = [];
3309                 thread = null;
3310                 tweenCount = 0;
3311             }
3312             else {
3313                 this.unRegister(tween);
3314             }
3315         };
3316
3317
3318         this.run = function() {
3319             for (var i = 0, len = queue.length; i < len; ++i) {
3320                 var tween = queue[i];
3321                 if (!tween || !tween.isAnimated()) {
3322                     continue;
3323                 }
3324
3325                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3326                 {
3327                     tween.currentFrame += 1;
3328
3329                     if (tween.useSeconds) {
3330                         correctFrame(tween);
3331                     }
3332                     tween._onTween.fire();
3333                 }
3334                 else {
3335                     Roo.lib.AnimMgr.stop(tween, i);
3336                 }
3337             }
3338         };
3339
3340         var getIndex = function(anim) {
3341             for (var i = 0, len = queue.length; i < len; ++i) {
3342                 if (queue[i] == anim) {
3343                     return i;
3344                 }
3345             }
3346             return -1;
3347         };
3348
3349
3350         var correctFrame = function(tween) {
3351             var frames = tween.totalFrames;
3352             var frame = tween.currentFrame;
3353             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3354             var elapsed = (new Date() - tween.getStartTime());
3355             var tweak = 0;
3356
3357             if (elapsed < tween.duration * 1000) {
3358                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3359             } else {
3360                 tweak = frames - (frame + 1);
3361             }
3362             if (tweak > 0 && isFinite(tweak)) {
3363                 if (tween.currentFrame + tweak >= frames) {
3364                     tweak = frames - (frame + 1);
3365                 }
3366
3367                 tween.currentFrame += tweak;
3368             }
3369         };
3370     };/*
3371  * Portions of this file are based on pieces of Yahoo User Interface Library
3372  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3373  * YUI licensed under the BSD License:
3374  * http://developer.yahoo.net/yui/license.txt
3375  * <script type="text/javascript">
3376  *
3377  */
3378 Roo.lib.Bezier = new function() {
3379
3380         this.getPosition = function(points, t) {
3381             var n = points.length;
3382             var tmp = [];
3383
3384             for (var i = 0; i < n; ++i) {
3385                 tmp[i] = [points[i][0], points[i][1]];
3386             }
3387
3388             for (var j = 1; j < n; ++j) {
3389                 for (i = 0; i < n - j; ++i) {
3390                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3391                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3392                 }
3393             }
3394
3395             return [ tmp[0][0], tmp[0][1] ];
3396
3397         };
3398     };/*
3399  * Portions of this file are based on pieces of Yahoo User Interface Library
3400  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3401  * YUI licensed under the BSD License:
3402  * http://developer.yahoo.net/yui/license.txt
3403  * <script type="text/javascript">
3404  *
3405  */
3406 (function() {
3407
3408     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3409         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3410     };
3411
3412     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3413
3414     var fly = Roo.lib.AnimBase.fly;
3415     var Y = Roo.lib;
3416     var superclass = Y.ColorAnim.superclass;
3417     var proto = Y.ColorAnim.prototype;
3418
3419     proto.toString = function() {
3420         var el = this.getEl();
3421         var id = el.id || el.tagName;
3422         return ("ColorAnim " + id);
3423     };
3424
3425     proto.patterns.color = /color$/i;
3426     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3427     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3428     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3429     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3430
3431
3432     proto.parseColor = function(s) {
3433         if (s.length == 3) {
3434             return s;
3435         }
3436
3437         var c = this.patterns.hex.exec(s);
3438         if (c && c.length == 4) {
3439             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3440         }
3441
3442         c = this.patterns.rgb.exec(s);
3443         if (c && c.length == 4) {
3444             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3445         }
3446
3447         c = this.patterns.hex3.exec(s);
3448         if (c && c.length == 4) {
3449             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3450         }
3451
3452         return null;
3453     };
3454     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3455     proto.getAttribute = function(attr) {
3456         var el = this.getEl();
3457         if (this.patterns.color.test(attr)) {
3458             var val = fly(el).getStyle(attr);
3459
3460             if (this.patterns.transparent.test(val)) {
3461                 var parent = el.parentNode;
3462                 val = fly(parent).getStyle(attr);
3463
3464                 while (parent && this.patterns.transparent.test(val)) {
3465                     parent = parent.parentNode;
3466                     val = fly(parent).getStyle(attr);
3467                     if (parent.tagName.toUpperCase() == 'HTML') {
3468                         val = '#fff';
3469                     }
3470                 }
3471             }
3472         } else {
3473             val = superclass.getAttribute.call(this, attr);
3474         }
3475
3476         return val;
3477     };
3478     proto.getAttribute = function(attr) {
3479         var el = this.getEl();
3480         if (this.patterns.color.test(attr)) {
3481             var val = fly(el).getStyle(attr);
3482
3483             if (this.patterns.transparent.test(val)) {
3484                 var parent = el.parentNode;
3485                 val = fly(parent).getStyle(attr);
3486
3487                 while (parent && this.patterns.transparent.test(val)) {
3488                     parent = parent.parentNode;
3489                     val = fly(parent).getStyle(attr);
3490                     if (parent.tagName.toUpperCase() == 'HTML') {
3491                         val = '#fff';
3492                     }
3493                 }
3494             }
3495         } else {
3496             val = superclass.getAttribute.call(this, attr);
3497         }
3498
3499         return val;
3500     };
3501
3502     proto.doMethod = function(attr, start, end) {
3503         var val;
3504
3505         if (this.patterns.color.test(attr)) {
3506             val = [];
3507             for (var i = 0, len = start.length; i < len; ++i) {
3508                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3509             }
3510
3511             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3512         }
3513         else {
3514             val = superclass.doMethod.call(this, attr, start, end);
3515         }
3516
3517         return val;
3518     };
3519
3520     proto.setRuntimeAttribute = function(attr) {
3521         superclass.setRuntimeAttribute.call(this, attr);
3522
3523         if (this.patterns.color.test(attr)) {
3524             var attributes = this.attributes;
3525             var start = this.parseColor(this.runtimeAttributes[attr].start);
3526             var end = this.parseColor(this.runtimeAttributes[attr].end);
3527
3528             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3529                 end = this.parseColor(attributes[attr].by);
3530
3531                 for (var i = 0, len = start.length; i < len; ++i) {
3532                     end[i] = start[i] + end[i];
3533                 }
3534             }
3535
3536             this.runtimeAttributes[attr].start = start;
3537             this.runtimeAttributes[attr].end = end;
3538         }
3539     };
3540 })();
3541
3542 /*
3543  * Portions of this file are based on pieces of Yahoo User Interface Library
3544  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545  * YUI licensed under the BSD License:
3546  * http://developer.yahoo.net/yui/license.txt
3547  * <script type="text/javascript">
3548  *
3549  */
3550 Roo.lib.Easing = {
3551
3552
3553     easeNone: function (t, b, c, d) {
3554         return c * t / d + b;
3555     },
3556
3557
3558     easeIn: function (t, b, c, d) {
3559         return c * (t /= d) * t + b;
3560     },
3561
3562
3563     easeOut: function (t, b, c, d) {
3564         return -c * (t /= d) * (t - 2) + b;
3565     },
3566
3567
3568     easeBoth: function (t, b, c, d) {
3569         if ((t /= d / 2) < 1) {
3570             return c / 2 * t * t + b;
3571         }
3572
3573         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3574     },
3575
3576
3577     easeInStrong: function (t, b, c, d) {
3578         return c * (t /= d) * t * t * t + b;
3579     },
3580
3581
3582     easeOutStrong: function (t, b, c, d) {
3583         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3584     },
3585
3586
3587     easeBothStrong: function (t, b, c, d) {
3588         if ((t /= d / 2) < 1) {
3589             return c / 2 * t * t * t * t + b;
3590         }
3591
3592         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3593     },
3594
3595
3596
3597     elasticIn: function (t, b, c, d, a, p) {
3598         if (t == 0) {
3599             return b;
3600         }
3601         if ((t /= d) == 1) {
3602             return b + c;
3603         }
3604         if (!p) {
3605             p = d * .3;
3606         }
3607
3608         if (!a || a < Math.abs(c)) {
3609             a = c;
3610             var s = p / 4;
3611         }
3612         else {
3613             var s = p / (2 * Math.PI) * Math.asin(c / a);
3614         }
3615
3616         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3617     },
3618
3619
3620     elasticOut: function (t, b, c, d, a, p) {
3621         if (t == 0) {
3622             return b;
3623         }
3624         if ((t /= d) == 1) {
3625             return b + c;
3626         }
3627         if (!p) {
3628             p = d * .3;
3629         }
3630
3631         if (!a || a < Math.abs(c)) {
3632             a = c;
3633             var s = p / 4;
3634         }
3635         else {
3636             var s = p / (2 * Math.PI) * Math.asin(c / a);
3637         }
3638
3639         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3640     },
3641
3642
3643     elasticBoth: function (t, b, c, d, a, p) {
3644         if (t == 0) {
3645             return b;
3646         }
3647
3648         if ((t /= d / 2) == 2) {
3649             return b + c;
3650         }
3651
3652         if (!p) {
3653             p = d * (.3 * 1.5);
3654         }
3655
3656         if (!a || a < Math.abs(c)) {
3657             a = c;
3658             var s = p / 4;
3659         }
3660         else {
3661             var s = p / (2 * Math.PI) * Math.asin(c / a);
3662         }
3663
3664         if (t < 1) {
3665             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3666                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3667         }
3668         return a * Math.pow(2, -10 * (t -= 1)) *
3669                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3670     },
3671
3672
3673
3674     backIn: function (t, b, c, d, s) {
3675         if (typeof s == 'undefined') {
3676             s = 1.70158;
3677         }
3678         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3679     },
3680
3681
3682     backOut: function (t, b, c, d, s) {
3683         if (typeof s == 'undefined') {
3684             s = 1.70158;
3685         }
3686         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3687     },
3688
3689
3690     backBoth: function (t, b, c, d, s) {
3691         if (typeof s == 'undefined') {
3692             s = 1.70158;
3693         }
3694
3695         if ((t /= d / 2 ) < 1) {
3696             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3697         }
3698         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3699     },
3700
3701
3702     bounceIn: function (t, b, c, d) {
3703         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3704     },
3705
3706
3707     bounceOut: function (t, b, c, d) {
3708         if ((t /= d) < (1 / 2.75)) {
3709             return c * (7.5625 * t * t) + b;
3710         } else if (t < (2 / 2.75)) {
3711             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3712         } else if (t < (2.5 / 2.75)) {
3713             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3714         }
3715         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3716     },
3717
3718
3719     bounceBoth: function (t, b, c, d) {
3720         if (t < d / 2) {
3721             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3722         }
3723         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3724     }
3725 };/*
3726  * Portions of this file are based on pieces of Yahoo User Interface Library
3727  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3728  * YUI licensed under the BSD License:
3729  * http://developer.yahoo.net/yui/license.txt
3730  * <script type="text/javascript">
3731  *
3732  */
3733     (function() {
3734         Roo.lib.Motion = function(el, attributes, duration, method) {
3735             if (el) {
3736                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3737             }
3738         };
3739
3740         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3741
3742
3743         var Y = Roo.lib;
3744         var superclass = Y.Motion.superclass;
3745         var proto = Y.Motion.prototype;
3746
3747         proto.toString = function() {
3748             var el = this.getEl();
3749             var id = el.id || el.tagName;
3750             return ("Motion " + id);
3751         };
3752
3753         proto.patterns.points = /^points$/i;
3754
3755         proto.setAttribute = function(attr, val, unit) {
3756             if (this.patterns.points.test(attr)) {
3757                 unit = unit || 'px';
3758                 superclass.setAttribute.call(this, 'left', val[0], unit);
3759                 superclass.setAttribute.call(this, 'top', val[1], unit);
3760             } else {
3761                 superclass.setAttribute.call(this, attr, val, unit);
3762             }
3763         };
3764
3765         proto.getAttribute = function(attr) {
3766             if (this.patterns.points.test(attr)) {
3767                 var val = [
3768                         superclass.getAttribute.call(this, 'left'),
3769                         superclass.getAttribute.call(this, 'top')
3770                         ];
3771             } else {
3772                 val = superclass.getAttribute.call(this, attr);
3773             }
3774
3775             return val;
3776         };
3777
3778         proto.doMethod = function(attr, start, end) {
3779             var val = null;
3780
3781             if (this.patterns.points.test(attr)) {
3782                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3783                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3784             } else {
3785                 val = superclass.doMethod.call(this, attr, start, end);
3786             }
3787             return val;
3788         };
3789
3790         proto.setRuntimeAttribute = function(attr) {
3791             if (this.patterns.points.test(attr)) {
3792                 var el = this.getEl();
3793                 var attributes = this.attributes;
3794                 var start;
3795                 var control = attributes['points']['control'] || [];
3796                 var end;
3797                 var i, len;
3798
3799                 if (control.length > 0 && !(control[0] instanceof Array)) {
3800                     control = [control];
3801                 } else {
3802                     var tmp = [];
3803                     for (i = 0,len = control.length; i < len; ++i) {
3804                         tmp[i] = control[i];
3805                     }
3806                     control = tmp;
3807                 }
3808
3809                 Roo.fly(el).position();
3810
3811                 if (isset(attributes['points']['from'])) {
3812                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3813                 }
3814                 else {
3815                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3816                 }
3817
3818                 start = this.getAttribute('points');
3819
3820
3821                 if (isset(attributes['points']['to'])) {
3822                     end = translateValues.call(this, attributes['points']['to'], start);
3823
3824                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3825                     for (i = 0,len = control.length; i < len; ++i) {
3826                         control[i] = translateValues.call(this, control[i], start);
3827                     }
3828
3829
3830                 } else if (isset(attributes['points']['by'])) {
3831                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3832
3833                     for (i = 0,len = control.length; i < len; ++i) {
3834                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3835                     }
3836                 }
3837
3838                 this.runtimeAttributes[attr] = [start];
3839
3840                 if (control.length > 0) {
3841                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3842                 }
3843
3844                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3845             }
3846             else {
3847                 superclass.setRuntimeAttribute.call(this, attr);
3848             }
3849         };
3850
3851         var translateValues = function(val, start) {
3852             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3853             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3854
3855             return val;
3856         };
3857
3858         var isset = function(prop) {
3859             return (typeof prop !== 'undefined');
3860         };
3861     })();
3862 /*
3863  * Portions of this file are based on pieces of Yahoo User Interface Library
3864  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3865  * YUI licensed under the BSD License:
3866  * http://developer.yahoo.net/yui/license.txt
3867  * <script type="text/javascript">
3868  *
3869  */
3870     (function() {
3871         Roo.lib.Scroll = function(el, attributes, duration, method) {
3872             if (el) {
3873                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3874             }
3875         };
3876
3877         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3878
3879
3880         var Y = Roo.lib;
3881         var superclass = Y.Scroll.superclass;
3882         var proto = Y.Scroll.prototype;
3883
3884         proto.toString = function() {
3885             var el = this.getEl();
3886             var id = el.id || el.tagName;
3887             return ("Scroll " + id);
3888         };
3889
3890         proto.doMethod = function(attr, start, end) {
3891             var val = null;
3892
3893             if (attr == 'scroll') {
3894                 val = [
3895                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3896                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3897                         ];
3898
3899             } else {
3900                 val = superclass.doMethod.call(this, attr, start, end);
3901             }
3902             return val;
3903         };
3904
3905         proto.getAttribute = function(attr) {
3906             var val = null;
3907             var el = this.getEl();
3908
3909             if (attr == 'scroll') {
3910                 val = [ el.scrollLeft, el.scrollTop ];
3911             } else {
3912                 val = superclass.getAttribute.call(this, attr);
3913             }
3914
3915             return val;
3916         };
3917
3918         proto.setAttribute = function(attr, val, unit) {
3919             var el = this.getEl();
3920
3921             if (attr == 'scroll') {
3922                 el.scrollLeft = val[0];
3923                 el.scrollTop = val[1];
3924             } else {
3925                 superclass.setAttribute.call(this, attr, val, unit);
3926             }
3927         };
3928     })();
3929 /*
3930  * Based on:
3931  * Ext JS Library 1.1.1
3932  * Copyright(c) 2006-2007, Ext JS, LLC.
3933  *
3934  * Originally Released Under LGPL - original licence link has changed is not relivant.
3935  *
3936  * Fork - LGPL
3937  * <script type="text/javascript">
3938  */
3939  
3940
3941 /**
3942  * @class Roo.DomHelper
3943  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3944  * 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>.
3945  * @singleton
3946  */
3947 Roo.DomHelper = function(){
3948     var tempTableEl = null;
3949     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3950     var tableRe = /^table|tbody|tr|td$/i;
3951     var xmlns = {};
3952     // build as innerHTML where available
3953     /** @ignore */
3954     var createHtml = function(o){
3955         if(typeof o == 'string'){
3956             return o;
3957         }
3958         var b = "";
3959         if(!o.tag){
3960             o.tag = "div";
3961         }
3962         b += "<" + o.tag;
3963         for(var attr in o){
3964             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3965             if(attr == "style"){
3966                 var s = o["style"];
3967                 if(typeof s == "function"){
3968                     s = s.call();
3969                 }
3970                 if(typeof s == "string"){
3971                     b += ' style="' + s + '"';
3972                 }else if(typeof s == "object"){
3973                     b += ' style="';
3974                     for(var key in s){
3975                         if(typeof s[key] != "function"){
3976                             b += key + ":" + s[key] + ";";
3977                         }
3978                     }
3979                     b += '"';
3980                 }
3981             }else{
3982                 if(attr == "cls"){
3983                     b += ' class="' + o["cls"] + '"';
3984                 }else if(attr == "htmlFor"){
3985                     b += ' for="' + o["htmlFor"] + '"';
3986                 }else{
3987                     b += " " + attr + '="' + o[attr] + '"';
3988                 }
3989             }
3990         }
3991         if(emptyTags.test(o.tag)){
3992             b += "/>";
3993         }else{
3994             b += ">";
3995             var cn = o.children || o.cn;
3996             if(cn){
3997                 //http://bugs.kde.org/show_bug.cgi?id=71506
3998                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3999                     for(var i = 0, len = cn.length; i < len; i++) {
4000                         b += createHtml(cn[i], b);
4001                     }
4002                 }else{
4003                     b += createHtml(cn, b);
4004                 }
4005             }
4006             if(o.html){
4007                 b += o.html;
4008             }
4009             b += "</" + o.tag + ">";
4010         }
4011         return b;
4012     };
4013
4014     // build as dom
4015     /** @ignore */
4016     var createDom = function(o, parentNode){
4017          
4018         // defininition craeted..
4019         var ns = false;
4020         if (o.ns && o.ns != 'html') {
4021                
4022             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4023                 xmlns[o.ns] = o.xmlns;
4024                 ns = o.xmlns;
4025             }
4026             if (typeof(xmlns[o.ns]) == 'undefined') {
4027                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4028             }
4029             ns = xmlns[o.ns];
4030         }
4031         
4032         
4033         if (typeof(o) == 'string') {
4034             return parentNode.appendChild(document.createTextNode(o));
4035         }
4036         o.tag = o.tag || div;
4037         if (o.ns && Roo.isIE) {
4038             ns = false;
4039             o.tag = o.ns + ':' + o.tag;
4040             
4041         }
4042         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4043         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4044         for(var attr in o){
4045             
4046             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4047                     attr == "style" || typeof o[attr] == "function") continue;
4048                     
4049             if(attr=="cls" && Roo.isIE){
4050                 el.className = o["cls"];
4051             }else{
4052                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4053                 else el[attr] = o[attr];
4054             }
4055         }
4056         Roo.DomHelper.applyStyles(el, o.style);
4057         var cn = o.children || o.cn;
4058         if(cn){
4059             //http://bugs.kde.org/show_bug.cgi?id=71506
4060              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4061                 for(var i = 0, len = cn.length; i < len; i++) {
4062                     createDom(cn[i], el);
4063                 }
4064             }else{
4065                 createDom(cn, el);
4066             }
4067         }
4068         if(o.html){
4069             el.innerHTML = o.html;
4070         }
4071         if(parentNode){
4072            parentNode.appendChild(el);
4073         }
4074         return el;
4075     };
4076
4077     var ieTable = function(depth, s, h, e){
4078         tempTableEl.innerHTML = [s, h, e].join('');
4079         var i = -1, el = tempTableEl;
4080         while(++i < depth){
4081             el = el.firstChild;
4082         }
4083         return el;
4084     };
4085
4086     // kill repeat to save bytes
4087     var ts = '<table>',
4088         te = '</table>',
4089         tbs = ts+'<tbody>',
4090         tbe = '</tbody>'+te,
4091         trs = tbs + '<tr>',
4092         tre = '</tr>'+tbe;
4093
4094     /**
4095      * @ignore
4096      * Nasty code for IE's broken table implementation
4097      */
4098     var insertIntoTable = function(tag, where, el, html){
4099         if(!tempTableEl){
4100             tempTableEl = document.createElement('div');
4101         }
4102         var node;
4103         var before = null;
4104         if(tag == 'td'){
4105             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4106                 return;
4107             }
4108             if(where == 'beforebegin'){
4109                 before = el;
4110                 el = el.parentNode;
4111             } else{
4112                 before = el.nextSibling;
4113                 el = el.parentNode;
4114             }
4115             node = ieTable(4, trs, html, tre);
4116         }
4117         else if(tag == 'tr'){
4118             if(where == 'beforebegin'){
4119                 before = el;
4120                 el = el.parentNode;
4121                 node = ieTable(3, tbs, html, tbe);
4122             } else if(where == 'afterend'){
4123                 before = el.nextSibling;
4124                 el = el.parentNode;
4125                 node = ieTable(3, tbs, html, tbe);
4126             } else{ // INTO a TR
4127                 if(where == 'afterbegin'){
4128                     before = el.firstChild;
4129                 }
4130                 node = ieTable(4, trs, html, tre);
4131             }
4132         } else if(tag == 'tbody'){
4133             if(where == 'beforebegin'){
4134                 before = el;
4135                 el = el.parentNode;
4136                 node = ieTable(2, ts, html, te);
4137             } else if(where == 'afterend'){
4138                 before = el.nextSibling;
4139                 el = el.parentNode;
4140                 node = ieTable(2, ts, html, te);
4141             } else{
4142                 if(where == 'afterbegin'){
4143                     before = el.firstChild;
4144                 }
4145                 node = ieTable(3, tbs, html, tbe);
4146             }
4147         } else{ // TABLE
4148             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4149                 return;
4150             }
4151             if(where == 'afterbegin'){
4152                 before = el.firstChild;
4153             }
4154             node = ieTable(2, ts, html, te);
4155         }
4156         el.insertBefore(node, before);
4157         return node;
4158     };
4159
4160     return {
4161     /** True to force the use of DOM instead of html fragments @type Boolean */
4162     useDom : false,
4163
4164     /**
4165      * Returns the markup for the passed Element(s) config
4166      * @param {Object} o The Dom object spec (and children)
4167      * @return {String}
4168      */
4169     markup : function(o){
4170         return createHtml(o);
4171     },
4172
4173     /**
4174      * Applies a style specification to an element
4175      * @param {String/HTMLElement} el The element to apply styles to
4176      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4177      * a function which returns such a specification.
4178      */
4179     applyStyles : function(el, styles){
4180         if(styles){
4181            el = Roo.fly(el);
4182            if(typeof styles == "string"){
4183                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4184                var matches;
4185                while ((matches = re.exec(styles)) != null){
4186                    el.setStyle(matches[1], matches[2]);
4187                }
4188            }else if (typeof styles == "object"){
4189                for (var style in styles){
4190                   el.setStyle(style, styles[style]);
4191                }
4192            }else if (typeof styles == "function"){
4193                 Roo.DomHelper.applyStyles(el, styles.call());
4194            }
4195         }
4196     },
4197
4198     /**
4199      * Inserts an HTML fragment into the Dom
4200      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4201      * @param {HTMLElement} el The context element
4202      * @param {String} html The HTML fragmenet
4203      * @return {HTMLElement} The new node
4204      */
4205     insertHtml : function(where, el, html){
4206         where = where.toLowerCase();
4207         if(el.insertAdjacentHTML){
4208             if(tableRe.test(el.tagName)){
4209                 var rs;
4210                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4211                     return rs;
4212                 }
4213             }
4214             switch(where){
4215                 case "beforebegin":
4216                     el.insertAdjacentHTML('BeforeBegin', html);
4217                     return el.previousSibling;
4218                 case "afterbegin":
4219                     el.insertAdjacentHTML('AfterBegin', html);
4220                     return el.firstChild;
4221                 case "beforeend":
4222                     el.insertAdjacentHTML('BeforeEnd', html);
4223                     return el.lastChild;
4224                 case "afterend":
4225                     el.insertAdjacentHTML('AfterEnd', html);
4226                     return el.nextSibling;
4227             }
4228             throw 'Illegal insertion point -> "' + where + '"';
4229         }
4230         var range = el.ownerDocument.createRange();
4231         var frag;
4232         switch(where){
4233              case "beforebegin":
4234                 range.setStartBefore(el);
4235                 frag = range.createContextualFragment(html);
4236                 el.parentNode.insertBefore(frag, el);
4237                 return el.previousSibling;
4238              case "afterbegin":
4239                 if(el.firstChild){
4240                     range.setStartBefore(el.firstChild);
4241                     frag = range.createContextualFragment(html);
4242                     el.insertBefore(frag, el.firstChild);
4243                     return el.firstChild;
4244                 }else{
4245                     el.innerHTML = html;
4246                     return el.firstChild;
4247                 }
4248             case "beforeend":
4249                 if(el.lastChild){
4250                     range.setStartAfter(el.lastChild);
4251                     frag = range.createContextualFragment(html);
4252                     el.appendChild(frag);
4253                     return el.lastChild;
4254                 }else{
4255                     el.innerHTML = html;
4256                     return el.lastChild;
4257                 }
4258             case "afterend":
4259                 range.setStartAfter(el);
4260                 frag = range.createContextualFragment(html);
4261                 el.parentNode.insertBefore(frag, el.nextSibling);
4262                 return el.nextSibling;
4263             }
4264             throw 'Illegal insertion point -> "' + where + '"';
4265     },
4266
4267     /**
4268      * Creates new Dom element(s) and inserts them before el
4269      * @param {String/HTMLElement/Element} el The context element
4270      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4271      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4272      * @return {HTMLElement/Roo.Element} The new node
4273      */
4274     insertBefore : function(el, o, returnElement){
4275         return this.doInsert(el, o, returnElement, "beforeBegin");
4276     },
4277
4278     /**
4279      * Creates new Dom element(s) and inserts them after el
4280      * @param {String/HTMLElement/Element} el The context element
4281      * @param {Object} o The Dom object spec (and children)
4282      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4283      * @return {HTMLElement/Roo.Element} The new node
4284      */
4285     insertAfter : function(el, o, returnElement){
4286         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4287     },
4288
4289     /**
4290      * Creates new Dom element(s) and inserts them as the first child of el
4291      * @param {String/HTMLElement/Element} el The context element
4292      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4293      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4294      * @return {HTMLElement/Roo.Element} The new node
4295      */
4296     insertFirst : function(el, o, returnElement){
4297         return this.doInsert(el, o, returnElement, "afterBegin");
4298     },
4299
4300     // private
4301     doInsert : function(el, o, returnElement, pos, sibling){
4302         el = Roo.getDom(el);
4303         var newNode;
4304         if(this.useDom || o.ns){
4305             newNode = createDom(o, null);
4306             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4307         }else{
4308             var html = createHtml(o);
4309             newNode = this.insertHtml(pos, el, html);
4310         }
4311         return returnElement ? Roo.get(newNode, true) : newNode;
4312     },
4313
4314     /**
4315      * Creates new Dom element(s) and appends them to el
4316      * @param {String/HTMLElement/Element} el The context element
4317      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4318      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4319      * @return {HTMLElement/Roo.Element} The new node
4320      */
4321     append : function(el, o, returnElement){
4322         el = Roo.getDom(el);
4323         var newNode;
4324         if(this.useDom || o.ns){
4325             newNode = createDom(o, null);
4326             el.appendChild(newNode);
4327         }else{
4328             var html = createHtml(o);
4329             newNode = this.insertHtml("beforeEnd", el, html);
4330         }
4331         return returnElement ? Roo.get(newNode, true) : newNode;
4332     },
4333
4334     /**
4335      * Creates new Dom element(s) and overwrites the contents of el with them
4336      * @param {String/HTMLElement/Element} el The context element
4337      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4338      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4339      * @return {HTMLElement/Roo.Element} The new node
4340      */
4341     overwrite : function(el, o, returnElement){
4342         el = Roo.getDom(el);
4343         if (o.ns) {
4344           
4345             while (el.childNodes.length) {
4346                 el.removeChild(el.firstChild);
4347             }
4348             createDom(o, el);
4349         } else {
4350             el.innerHTML = createHtml(o);   
4351         }
4352         
4353         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4354     },
4355
4356     /**
4357      * Creates a new Roo.DomHelper.Template from the Dom object spec
4358      * @param {Object} o The Dom object spec (and children)
4359      * @return {Roo.DomHelper.Template} The new template
4360      */
4361     createTemplate : function(o){
4362         var html = createHtml(o);
4363         return new Roo.Template(html);
4364     }
4365     };
4366 }();
4367 /*
4368  * Based on:
4369  * Ext JS Library 1.1.1
4370  * Copyright(c) 2006-2007, Ext JS, LLC.
4371  *
4372  * Originally Released Under LGPL - original licence link has changed is not relivant.
4373  *
4374  * Fork - LGPL
4375  * <script type="text/javascript">
4376  */
4377  
4378 /**
4379 * @class Roo.Template
4380 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4381 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4382 * Usage:
4383 <pre><code>
4384 var t = new Roo.Template(
4385     '&lt;div name="{id}"&gt;',
4386         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
4387     '&lt;/div&gt;'
4388 );
4389 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4390 </code></pre>
4391 * 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>. 
4392 * @constructor
4393 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4394 */
4395 Roo.Template = function(html){
4396     if(html instanceof Array){
4397         html = html.join("");
4398     }else if(arguments.length > 1){
4399         html = Array.prototype.join.call(arguments, "");
4400     }
4401     /**@private*/
4402     this.html = html;
4403     
4404 };
4405 Roo.Template.prototype = {
4406     /**
4407      * Returns an HTML fragment of this template with the specified values applied.
4408      * @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'})
4409      * @return {String} The HTML fragment
4410      */
4411     applyTemplate : function(values){
4412         if(this.compiled){
4413             return this.compiled(values);
4414         }
4415         var useF = this.disableFormats !== true;
4416         var fm = Roo.util.Format, tpl = this;
4417         var fn = function(m, name, format, args){
4418             if(format && useF){
4419                 if(format.substr(0, 5) == "this."){
4420                     return tpl.call(format.substr(5), values[name], values);
4421                 }else{
4422                     if(args){
4423                         // quoted values are required for strings in compiled templates, 
4424                         // but for non compiled we need to strip them
4425                         // quoted reversed for jsmin
4426                         var re = /^\s*['"](.*)["']\s*$/;
4427                         args = args.split(',');
4428                         for(var i = 0, len = args.length; i < len; i++){
4429                             args[i] = args[i].replace(re, "$1");
4430                         }
4431                         args = [values[name]].concat(args);
4432                     }else{
4433                         args = [values[name]];
4434                     }
4435                     return fm[format].apply(fm, args);
4436                 }
4437             }else{
4438                 return values[name] !== undefined ? values[name] : "";
4439             }
4440         };
4441         return this.html.replace(this.re, fn);
4442     },
4443     
4444     /**
4445      * Sets the HTML used as the template and optionally compiles it.
4446      * @param {String} html
4447      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4448      * @return {Roo.Template} this
4449      */
4450     set : function(html, compile){
4451         this.html = html;
4452         this.compiled = null;
4453         if(compile){
4454             this.compile();
4455         }
4456         return this;
4457     },
4458     
4459     /**
4460      * True to disable format functions (defaults to false)
4461      * @type Boolean
4462      */
4463     disableFormats : false,
4464     
4465     /**
4466     * The regular expression used to match template variables 
4467     * @type RegExp
4468     * @property 
4469     */
4470     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4471     
4472     /**
4473      * Compiles the template into an internal function, eliminating the RegEx overhead.
4474      * @return {Roo.Template} this
4475      */
4476     compile : function(){
4477         var fm = Roo.util.Format;
4478         var useF = this.disableFormats !== true;
4479         var sep = Roo.isGecko ? "+" : ",";
4480         var fn = function(m, name, format, args){
4481             if(format && useF){
4482                 args = args ? ',' + args : "";
4483                 if(format.substr(0, 5) != "this."){
4484                     format = "fm." + format + '(';
4485                 }else{
4486                     format = 'this.call("'+ format.substr(5) + '", ';
4487                     args = ", values";
4488                 }
4489             }else{
4490                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4491             }
4492             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4493         };
4494         var body;
4495         // branched to use + in gecko and [].join() in others
4496         if(Roo.isGecko){
4497             body = "this.compiled = function(values){ return '" +
4498                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4499                     "';};";
4500         }else{
4501             body = ["this.compiled = function(values){ return ['"];
4502             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4503             body.push("'].join('');};");
4504             body = body.join('');
4505         }
4506         /**
4507          * eval:var:values
4508          * eval:var:fm
4509          */
4510         eval(body);
4511         return this;
4512     },
4513     
4514     // private function used to call members
4515     call : function(fnName, value, allValues){
4516         return this[fnName](value, allValues);
4517     },
4518     
4519     /**
4520      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4521      * @param {String/HTMLElement/Roo.Element} el The context element
4522      * @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'})
4523      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4524      * @return {HTMLElement/Roo.Element} The new node or Element
4525      */
4526     insertFirst: function(el, values, returnElement){
4527         return this.doInsert('afterBegin', el, values, returnElement);
4528     },
4529
4530     /**
4531      * Applies the supplied values to the template and inserts the new node(s) before el.
4532      * @param {String/HTMLElement/Roo.Element} el The context element
4533      * @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'})
4534      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4535      * @return {HTMLElement/Roo.Element} The new node or Element
4536      */
4537     insertBefore: function(el, values, returnElement){
4538         return this.doInsert('beforeBegin', el, values, returnElement);
4539     },
4540
4541     /**
4542      * Applies the supplied values to the template and inserts the new node(s) after el.
4543      * @param {String/HTMLElement/Roo.Element} el The context element
4544      * @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'})
4545      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4546      * @return {HTMLElement/Roo.Element} The new node or Element
4547      */
4548     insertAfter : function(el, values, returnElement){
4549         return this.doInsert('afterEnd', el, values, returnElement);
4550     },
4551     
4552     /**
4553      * Applies the supplied values to the template and appends the new node(s) to el.
4554      * @param {String/HTMLElement/Roo.Element} el The context element
4555      * @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'})
4556      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4557      * @return {HTMLElement/Roo.Element} The new node or Element
4558      */
4559     append : function(el, values, returnElement){
4560         return this.doInsert('beforeEnd', el, values, returnElement);
4561     },
4562
4563     doInsert : function(where, el, values, returnEl){
4564         el = Roo.getDom(el);
4565         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4566         return returnEl ? Roo.get(newNode, true) : newNode;
4567     },
4568
4569     /**
4570      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4571      * @param {String/HTMLElement/Roo.Element} el The context element
4572      * @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'})
4573      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4574      * @return {HTMLElement/Roo.Element} The new node or Element
4575      */
4576     overwrite : function(el, values, returnElement){
4577         el = Roo.getDom(el);
4578         el.innerHTML = this.applyTemplate(values);
4579         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4580     }
4581 };
4582 /**
4583  * Alias for {@link #applyTemplate}
4584  * @method
4585  */
4586 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4587
4588 // backwards compat
4589 Roo.DomHelper.Template = Roo.Template;
4590
4591 /**
4592  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4593  * @param {String/HTMLElement} el A DOM element or its id
4594  * @returns {Roo.Template} The created template
4595  * @static
4596  */
4597 Roo.Template.from = function(el){
4598     el = Roo.getDom(el);
4599     return new Roo.Template(el.value || el.innerHTML);
4600 };/*
4601  * Based on:
4602  * Ext JS Library 1.1.1
4603  * Copyright(c) 2006-2007, Ext JS, LLC.
4604  *
4605  * Originally Released Under LGPL - original licence link has changed is not relivant.
4606  *
4607  * Fork - LGPL
4608  * <script type="text/javascript">
4609  */
4610  
4611
4612 /*
4613  * This is code is also distributed under MIT license for use
4614  * with jQuery and prototype JavaScript libraries.
4615  */
4616 /**
4617  * @class Roo.DomQuery
4618 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).
4619 <p>
4620 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>
4621
4622 <p>
4623 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.
4624 </p>
4625 <h4>Element Selectors:</h4>
4626 <ul class="list">
4627     <li> <b>*</b> any element</li>
4628     <li> <b>E</b> an element with the tag E</li>
4629     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4630     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4631     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4632     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4633 </ul>
4634 <h4>Attribute Selectors:</h4>
4635 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4636 <ul class="list">
4637     <li> <b>E[foo]</b> has an attribute "foo"</li>
4638     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4639     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4640     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4641     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4642     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4643     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4644 </ul>
4645 <h4>Pseudo Classes:</h4>
4646 <ul class="list">
4647     <li> <b>E:first-child</b> E is the first child of its parent</li>
4648     <li> <b>E:last-child</b> E is the last child of its parent</li>
4649     <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>
4650     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4651     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4652     <li> <b>E:only-child</b> E is the only child of its parent</li>
4653     <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>
4654     <li> <b>E:first</b> the first E in the resultset</li>
4655     <li> <b>E:last</b> the last E in the resultset</li>
4656     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4657     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4658     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4659     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4660     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4661     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4662     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4663     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4664     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4665 </ul>
4666 <h4>CSS Value Selectors:</h4>
4667 <ul class="list">
4668     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4669     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4670     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4671     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4672     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4673     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4674 </ul>
4675  * @singleton
4676  */
4677 Roo.DomQuery = function(){
4678     var cache = {}, simpleCache = {}, valueCache = {};
4679     var nonSpace = /\S/;
4680     var trimRe = /^\s+|\s+$/g;
4681     var tplRe = /\{(\d+)\}/g;
4682     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4683     var tagTokenRe = /^(#)?([\w-\*]+)/;
4684     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4685
4686     function child(p, index){
4687         var i = 0;
4688         var n = p.firstChild;
4689         while(n){
4690             if(n.nodeType == 1){
4691                if(++i == index){
4692                    return n;
4693                }
4694             }
4695             n = n.nextSibling;
4696         }
4697         return null;
4698     };
4699
4700     function next(n){
4701         while((n = n.nextSibling) && n.nodeType != 1);
4702         return n;
4703     };
4704
4705     function prev(n){
4706         while((n = n.previousSibling) && n.nodeType != 1);
4707         return n;
4708     };
4709
4710     function children(d){
4711         var n = d.firstChild, ni = -1;
4712             while(n){
4713                 var nx = n.nextSibling;
4714                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4715                     d.removeChild(n);
4716                 }else{
4717                     n.nodeIndex = ++ni;
4718                 }
4719                 n = nx;
4720             }
4721             return this;
4722         };
4723
4724     function byClassName(c, a, v){
4725         if(!v){
4726             return c;
4727         }
4728         var r = [], ri = -1, cn;
4729         for(var i = 0, ci; ci = c[i]; i++){
4730             if((' '+ci.className+' ').indexOf(v) != -1){
4731                 r[++ri] = ci;
4732             }
4733         }
4734         return r;
4735     };
4736
4737     function attrValue(n, attr){
4738         if(!n.tagName && typeof n.length != "undefined"){
4739             n = n[0];
4740         }
4741         if(!n){
4742             return null;
4743         }
4744         if(attr == "for"){
4745             return n.htmlFor;
4746         }
4747         if(attr == "class" || attr == "className"){
4748             return n.className;
4749         }
4750         return n.getAttribute(attr) || n[attr];
4751
4752     };
4753
4754     function getNodes(ns, mode, tagName){
4755         var result = [], ri = -1, cs;
4756         if(!ns){
4757             return result;
4758         }
4759         tagName = tagName || "*";
4760         if(typeof ns.getElementsByTagName != "undefined"){
4761             ns = [ns];
4762         }
4763         if(!mode){
4764             for(var i = 0, ni; ni = ns[i]; i++){
4765                 cs = ni.getElementsByTagName(tagName);
4766                 for(var j = 0, ci; ci = cs[j]; j++){
4767                     result[++ri] = ci;
4768                 }
4769             }
4770         }else if(mode == "/" || mode == ">"){
4771             var utag = tagName.toUpperCase();
4772             for(var i = 0, ni, cn; ni = ns[i]; i++){
4773                 cn = ni.children || ni.childNodes;
4774                 for(var j = 0, cj; cj = cn[j]; j++){
4775                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4776                         result[++ri] = cj;
4777                     }
4778                 }
4779             }
4780         }else if(mode == "+"){
4781             var utag = tagName.toUpperCase();
4782             for(var i = 0, n; n = ns[i]; i++){
4783                 while((n = n.nextSibling) && n.nodeType != 1);
4784                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4785                     result[++ri] = n;
4786                 }
4787             }
4788         }else if(mode == "~"){
4789             for(var i = 0, n; n = ns[i]; i++){
4790                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4791                 if(n){
4792                     result[++ri] = n;
4793                 }
4794             }
4795         }
4796         return result;
4797     };
4798
4799     function concat(a, b){
4800         if(b.slice){
4801             return a.concat(b);
4802         }
4803         for(var i = 0, l = b.length; i < l; i++){
4804             a[a.length] = b[i];
4805         }
4806         return a;
4807     }
4808
4809     function byTag(cs, tagName){
4810         if(cs.tagName || cs == document){
4811             cs = [cs];
4812         }
4813         if(!tagName){
4814             return cs;
4815         }
4816         var r = [], ri = -1;
4817         tagName = tagName.toLowerCase();
4818         for(var i = 0, ci; ci = cs[i]; i++){
4819             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4820                 r[++ri] = ci;
4821             }
4822         }
4823         return r;
4824     };
4825
4826     function byId(cs, attr, id){
4827         if(cs.tagName || cs == document){
4828             cs = [cs];
4829         }
4830         if(!id){
4831             return cs;
4832         }
4833         var r = [], ri = -1;
4834         for(var i = 0,ci; ci = cs[i]; i++){
4835             if(ci && ci.id == id){
4836                 r[++ri] = ci;
4837                 return r;
4838             }
4839         }
4840         return r;
4841     };
4842
4843     function byAttribute(cs, attr, value, op, custom){
4844         var r = [], ri = -1, st = custom=="{";
4845         var f = Roo.DomQuery.operators[op];
4846         for(var i = 0, ci; ci = cs[i]; i++){
4847             var a;
4848             if(st){
4849                 a = Roo.DomQuery.getStyle(ci, attr);
4850             }
4851             else if(attr == "class" || attr == "className"){
4852                 a = ci.className;
4853             }else if(attr == "for"){
4854                 a = ci.htmlFor;
4855             }else if(attr == "href"){
4856                 a = ci.getAttribute("href", 2);
4857             }else{
4858                 a = ci.getAttribute(attr);
4859             }
4860             if((f && f(a, value)) || (!f && a)){
4861                 r[++ri] = ci;
4862             }
4863         }
4864         return r;
4865     };
4866
4867     function byPseudo(cs, name, value){
4868         return Roo.DomQuery.pseudos[name](cs, value);
4869     };
4870
4871     // This is for IE MSXML which does not support expandos.
4872     // IE runs the same speed using setAttribute, however FF slows way down
4873     // and Safari completely fails so they need to continue to use expandos.
4874     var isIE = window.ActiveXObject ? true : false;
4875
4876     // this eval is stop the compressor from
4877     // renaming the variable to something shorter
4878     
4879     /** eval:var:batch */
4880     var batch = 30803; 
4881
4882     var key = 30803;
4883
4884     function nodupIEXml(cs){
4885         var d = ++key;
4886         cs[0].setAttribute("_nodup", d);
4887         var r = [cs[0]];
4888         for(var i = 1, len = cs.length; i < len; i++){
4889             var c = cs[i];
4890             if(!c.getAttribute("_nodup") != d){
4891                 c.setAttribute("_nodup", d);
4892                 r[r.length] = c;
4893             }
4894         }
4895         for(var i = 0, len = cs.length; i < len; i++){
4896             cs[i].removeAttribute("_nodup");
4897         }
4898         return r;
4899     }
4900
4901     function nodup(cs){
4902         if(!cs){
4903             return [];
4904         }
4905         var len = cs.length, c, i, r = cs, cj, ri = -1;
4906         if(!len || typeof cs.nodeType != "undefined" || len == 1){
4907             return cs;
4908         }
4909         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4910             return nodupIEXml(cs);
4911         }
4912         var d = ++key;
4913         cs[0]._nodup = d;
4914         for(i = 1; c = cs[i]; i++){
4915             if(c._nodup != d){
4916                 c._nodup = d;
4917             }else{
4918                 r = [];
4919                 for(var j = 0; j < i; j++){
4920                     r[++ri] = cs[j];
4921                 }
4922                 for(j = i+1; cj = cs[j]; j++){
4923                     if(cj._nodup != d){
4924                         cj._nodup = d;
4925                         r[++ri] = cj;
4926                     }
4927                 }
4928                 return r;
4929             }
4930         }
4931         return r;
4932     }
4933
4934     function quickDiffIEXml(c1, c2){
4935         var d = ++key;
4936         for(var i = 0, len = c1.length; i < len; i++){
4937             c1[i].setAttribute("_qdiff", d);
4938         }
4939         var r = [];
4940         for(var i = 0, len = c2.length; i < len; i++){
4941             if(c2[i].getAttribute("_qdiff") != d){
4942                 r[r.length] = c2[i];
4943             }
4944         }
4945         for(var i = 0, len = c1.length; i < len; i++){
4946            c1[i].removeAttribute("_qdiff");
4947         }
4948         return r;
4949     }
4950
4951     function quickDiff(c1, c2){
4952         var len1 = c1.length;
4953         if(!len1){
4954             return c2;
4955         }
4956         if(isIE && c1[0].selectSingleNode){
4957             return quickDiffIEXml(c1, c2);
4958         }
4959         var d = ++key;
4960         for(var i = 0; i < len1; i++){
4961             c1[i]._qdiff = d;
4962         }
4963         var r = [];
4964         for(var i = 0, len = c2.length; i < len; i++){
4965             if(c2[i]._qdiff != d){
4966                 r[r.length] = c2[i];
4967             }
4968         }
4969         return r;
4970     }
4971
4972     function quickId(ns, mode, root, id){
4973         if(ns == root){
4974            var d = root.ownerDocument || root;
4975            return d.getElementById(id);
4976         }
4977         ns = getNodes(ns, mode, "*");
4978         return byId(ns, null, id);
4979     }
4980
4981     return {
4982         getStyle : function(el, name){
4983             return Roo.fly(el).getStyle(name);
4984         },
4985         /**
4986          * Compiles a selector/xpath query into a reusable function. The returned function
4987          * takes one parameter "root" (optional), which is the context node from where the query should start.
4988          * @param {String} selector The selector/xpath query
4989          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4990          * @return {Function}
4991          */
4992         compile : function(path, type){
4993             type = type || "select";
4994             
4995             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4996             var q = path, mode, lq;
4997             var tk = Roo.DomQuery.matchers;
4998             var tklen = tk.length;
4999             var mm;
5000
5001             // accept leading mode switch
5002             var lmode = q.match(modeRe);
5003             if(lmode && lmode[1]){
5004                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5005                 q = q.replace(lmode[1], "");
5006             }
5007             // strip leading slashes
5008             while(path.substr(0, 1)=="/"){
5009                 path = path.substr(1);
5010             }
5011
5012             while(q && lq != q){
5013                 lq = q;
5014                 var tm = q.match(tagTokenRe);
5015                 if(type == "select"){
5016                     if(tm){
5017                         if(tm[1] == "#"){
5018                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5019                         }else{
5020                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5021                         }
5022                         q = q.replace(tm[0], "");
5023                     }else if(q.substr(0, 1) != '@'){
5024                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5025                     }
5026                 }else{
5027                     if(tm){
5028                         if(tm[1] == "#"){
5029                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5030                         }else{
5031                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5032                         }
5033                         q = q.replace(tm[0], "");
5034                     }
5035                 }
5036                 while(!(mm = q.match(modeRe))){
5037                     var matched = false;
5038                     for(var j = 0; j < tklen; j++){
5039                         var t = tk[j];
5040                         var m = q.match(t.re);
5041                         if(m){
5042                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5043                                                     return m[i];
5044                                                 });
5045                             q = q.replace(m[0], "");
5046                             matched = true;
5047                             break;
5048                         }
5049                     }
5050                     // prevent infinite loop on bad selector
5051                     if(!matched){
5052                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5053                     }
5054                 }
5055                 if(mm[1]){
5056                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5057                     q = q.replace(mm[1], "");
5058                 }
5059             }
5060             fn[fn.length] = "return nodup(n);\n}";
5061             
5062              /** 
5063               * list of variables that need from compression as they are used by eval.
5064              *  eval:var:batch 
5065              *  eval:var:nodup
5066              *  eval:var:byTag
5067              *  eval:var:ById
5068              *  eval:var:getNodes
5069              *  eval:var:quickId
5070              *  eval:var:mode
5071              *  eval:var:root
5072              *  eval:var:n
5073              *  eval:var:byClassName
5074              *  eval:var:byPseudo
5075              *  eval:var:byAttribute
5076              *  eval:var:attrValue
5077              * 
5078              **/ 
5079             eval(fn.join(""));
5080             return f;
5081         },
5082
5083         /**
5084          * Selects a group of elements.
5085          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5086          * @param {Node} root (optional) The start of the query (defaults to document).
5087          * @return {Array}
5088          */
5089         select : function(path, root, type){
5090             if(!root || root == document){
5091                 root = document;
5092             }
5093             if(typeof root == "string"){
5094                 root = document.getElementById(root);
5095             }
5096             var paths = path.split(",");
5097             var results = [];
5098             for(var i = 0, len = paths.length; i < len; i++){
5099                 var p = paths[i].replace(trimRe, "");
5100                 if(!cache[p]){
5101                     cache[p] = Roo.DomQuery.compile(p);
5102                     if(!cache[p]){
5103                         throw p + " is not a valid selector";
5104                     }
5105                 }
5106                 var result = cache[p](root);
5107                 if(result && result != document){
5108                     results = results.concat(result);
5109                 }
5110             }
5111             if(paths.length > 1){
5112                 return nodup(results);
5113             }
5114             return results;
5115         },
5116
5117         /**
5118          * Selects a single element.
5119          * @param {String} selector The selector/xpath query
5120          * @param {Node} root (optional) The start of the query (defaults to document).
5121          * @return {Element}
5122          */
5123         selectNode : function(path, root){
5124             return Roo.DomQuery.select(path, root)[0];
5125         },
5126
5127         /**
5128          * Selects the value of a node, optionally replacing null with the defaultValue.
5129          * @param {String} selector The selector/xpath query
5130          * @param {Node} root (optional) The start of the query (defaults to document).
5131          * @param {String} defaultValue
5132          */
5133         selectValue : function(path, root, defaultValue){
5134             path = path.replace(trimRe, "");
5135             if(!valueCache[path]){
5136                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5137             }
5138             var n = valueCache[path](root);
5139             n = n[0] ? n[0] : n;
5140             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5141             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5142         },
5143
5144         /**
5145          * Selects the value of a node, parsing integers and floats.
5146          * @param {String} selector The selector/xpath query
5147          * @param {Node} root (optional) The start of the query (defaults to document).
5148          * @param {Number} defaultValue
5149          * @return {Number}
5150          */
5151         selectNumber : function(path, root, defaultValue){
5152             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5153             return parseFloat(v);
5154         },
5155
5156         /**
5157          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5158          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5159          * @param {String} selector The simple selector to test
5160          * @return {Boolean}
5161          */
5162         is : function(el, ss){
5163             if(typeof el == "string"){
5164                 el = document.getElementById(el);
5165             }
5166             var isArray = (el instanceof Array);
5167             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5168             return isArray ? (result.length == el.length) : (result.length > 0);
5169         },
5170
5171         /**
5172          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5173          * @param {Array} el An array of elements to filter
5174          * @param {String} selector The simple selector to test
5175          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5176          * the selector instead of the ones that match
5177          * @return {Array}
5178          */
5179         filter : function(els, ss, nonMatches){
5180             ss = ss.replace(trimRe, "");
5181             if(!simpleCache[ss]){
5182                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5183             }
5184             var result = simpleCache[ss](els);
5185             return nonMatches ? quickDiff(result, els) : result;
5186         },
5187
5188         /**
5189          * Collection of matching regular expressions and code snippets.
5190          */
5191         matchers : [{
5192                 re: /^\.([\w-]+)/,
5193                 select: 'n = byClassName(n, null, " {1} ");'
5194             }, {
5195                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5196                 select: 'n = byPseudo(n, "{1}", "{2}");'
5197             },{
5198                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5199                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5200             }, {
5201                 re: /^#([\w-]+)/,
5202                 select: 'n = byId(n, null, "{1}");'
5203             },{
5204                 re: /^@([\w-]+)/,
5205                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5206             }
5207         ],
5208
5209         /**
5210          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5211          * 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;.
5212          */
5213         operators : {
5214             "=" : function(a, v){
5215                 return a == v;
5216             },
5217             "!=" : function(a, v){
5218                 return a != v;
5219             },
5220             "^=" : function(a, v){
5221                 return a && a.substr(0, v.length) == v;
5222             },
5223             "$=" : function(a, v){
5224                 return a && a.substr(a.length-v.length) == v;
5225             },
5226             "*=" : function(a, v){
5227                 return a && a.indexOf(v) !== -1;
5228             },
5229             "%=" : function(a, v){
5230                 return (a % v) == 0;
5231             },
5232             "|=" : function(a, v){
5233                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5234             },
5235             "~=" : function(a, v){
5236                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5237             }
5238         },
5239
5240         /**
5241          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5242          * and the argument (if any) supplied in the selector.
5243          */
5244         pseudos : {
5245             "first-child" : function(c){
5246                 var r = [], ri = -1, n;
5247                 for(var i = 0, ci; ci = n = c[i]; i++){
5248                     while((n = n.previousSibling) && n.nodeType != 1);
5249                     if(!n){
5250                         r[++ri] = ci;
5251                     }
5252                 }
5253                 return r;
5254             },
5255
5256             "last-child" : function(c){
5257                 var r = [], ri = -1, n;
5258                 for(var i = 0, ci; ci = n = c[i]; i++){
5259                     while((n = n.nextSibling) && n.nodeType != 1);
5260                     if(!n){
5261                         r[++ri] = ci;
5262                     }
5263                 }
5264                 return r;
5265             },
5266
5267             "nth-child" : function(c, a) {
5268                 var r = [], ri = -1;
5269                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5270                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5271                 for(var i = 0, n; n = c[i]; i++){
5272                     var pn = n.parentNode;
5273                     if (batch != pn._batch) {
5274                         var j = 0;
5275                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5276                             if(cn.nodeType == 1){
5277                                cn.nodeIndex = ++j;
5278                             }
5279                         }
5280                         pn._batch = batch;
5281                     }
5282                     if (f == 1) {
5283                         if (l == 0 || n.nodeIndex == l){
5284                             r[++ri] = n;
5285                         }
5286                     } else if ((n.nodeIndex + l) % f == 0){
5287                         r[++ri] = n;
5288                     }
5289                 }
5290
5291                 return r;
5292             },
5293
5294             "only-child" : function(c){
5295                 var r = [], ri = -1;;
5296                 for(var i = 0, ci; ci = c[i]; i++){
5297                     if(!prev(ci) && !next(ci)){
5298                         r[++ri] = ci;
5299                     }
5300                 }
5301                 return r;
5302             },
5303
5304             "empty" : function(c){
5305                 var r = [], ri = -1;
5306                 for(var i = 0, ci; ci = c[i]; i++){
5307                     var cns = ci.childNodes, j = 0, cn, empty = true;
5308                     while(cn = cns[j]){
5309                         ++j;
5310                         if(cn.nodeType == 1 || cn.nodeType == 3){
5311                             empty = false;
5312                             break;
5313                         }
5314                     }
5315                     if(empty){
5316                         r[++ri] = ci;
5317                     }
5318                 }
5319                 return r;
5320             },
5321
5322             "contains" : function(c, v){
5323                 var r = [], ri = -1;
5324                 for(var i = 0, ci; ci = c[i]; i++){
5325                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5326                         r[++ri] = ci;
5327                     }
5328                 }
5329                 return r;
5330             },
5331
5332             "nodeValue" : function(c, v){
5333                 var r = [], ri = -1;
5334                 for(var i = 0, ci; ci = c[i]; i++){
5335                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5336                         r[++ri] = ci;
5337                     }
5338                 }
5339                 return r;
5340             },
5341
5342             "checked" : function(c){
5343                 var r = [], ri = -1;
5344                 for(var i = 0, ci; ci = c[i]; i++){
5345                     if(ci.checked == true){
5346                         r[++ri] = ci;
5347                     }
5348                 }
5349                 return r;
5350             },
5351
5352             "not" : function(c, ss){
5353                 return Roo.DomQuery.filter(c, ss, true);
5354             },
5355
5356             "odd" : function(c){
5357                 return this["nth-child"](c, "odd");
5358             },
5359
5360             "even" : function(c){
5361                 return this["nth-child"](c, "even");
5362             },
5363
5364             "nth" : function(c, a){
5365                 return c[a-1] || [];
5366             },
5367
5368             "first" : function(c){
5369                 return c[0] || [];
5370             },
5371
5372             "last" : function(c){
5373                 return c[c.length-1] || [];
5374             },
5375
5376             "has" : function(c, ss){
5377                 var s = Roo.DomQuery.select;
5378                 var r = [], ri = -1;
5379                 for(var i = 0, ci; ci = c[i]; i++){
5380                     if(s(ss, ci).length > 0){
5381                         r[++ri] = ci;
5382                     }
5383                 }
5384                 return r;
5385             },
5386
5387             "next" : function(c, ss){
5388                 var is = Roo.DomQuery.is;
5389                 var r = [], ri = -1;
5390                 for(var i = 0, ci; ci = c[i]; i++){
5391                     var n = next(ci);
5392                     if(n && is(n, ss)){
5393                         r[++ri] = ci;
5394                     }
5395                 }
5396                 return r;
5397             },
5398
5399             "prev" : function(c, ss){
5400                 var is = Roo.DomQuery.is;
5401                 var r = [], ri = -1;
5402                 for(var i = 0, ci; ci = c[i]; i++){
5403                     var n = prev(ci);
5404                     if(n && is(n, ss)){
5405                         r[++ri] = ci;
5406                     }
5407                 }
5408                 return r;
5409             }
5410         }
5411     };
5412 }();
5413
5414 /**
5415  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5416  * @param {String} path The selector/xpath query
5417  * @param {Node} root (optional) The start of the query (defaults to document).
5418  * @return {Array}
5419  * @member Roo
5420  * @method query
5421  */
5422 Roo.query = Roo.DomQuery.select;
5423 /*
5424  * Based on:
5425  * Ext JS Library 1.1.1
5426  * Copyright(c) 2006-2007, Ext JS, LLC.
5427  *
5428  * Originally Released Under LGPL - original licence link has changed is not relivant.
5429  *
5430  * Fork - LGPL
5431  * <script type="text/javascript">
5432  */
5433
5434 /**
5435  * @class Roo.util.Observable
5436  * Base class that provides a common interface for publishing events. Subclasses are expected to
5437  * to have a property "events" with all the events defined.<br>
5438  * For example:
5439  * <pre><code>
5440  Employee = function(name){
5441     this.name = name;
5442     this.addEvents({
5443         "fired" : true,
5444         "quit" : true
5445     });
5446  }
5447  Roo.extend(Employee, Roo.util.Observable);
5448 </code></pre>
5449  * @param {Object} config properties to use (incuding events / listeners)
5450  */
5451
5452 Roo.util.Observable = function(cfg){
5453     
5454     cfg = cfg|| {};
5455     this.addEvents(cfg.events || {});
5456     if (cfg.events) {
5457         delete cfg.events; // make sure
5458     }
5459      
5460     Roo.apply(this, cfg);
5461     
5462     if(this.listeners){
5463         this.on(this.listeners);
5464         delete this.listeners;
5465     }
5466 };
5467 Roo.util.Observable.prototype = {
5468     /** 
5469  * @cfg {Object} listeners  list of events and functions to call for this object, 
5470  * For example :
5471  * <pre><code>
5472     listeners :  { 
5473        'click' : function(e) {
5474            ..... 
5475         } ,
5476         .... 
5477     } 
5478   </code></pre>
5479  */
5480     
5481     
5482     /**
5483      * Fires the specified event with the passed parameters (minus the event name).
5484      * @param {String} eventName
5485      * @param {Object...} args Variable number of parameters are passed to handlers
5486      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5487      */
5488     fireEvent : function(){
5489         var ce = this.events[arguments[0].toLowerCase()];
5490         if(typeof ce == "object"){
5491             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5492         }else{
5493             return true;
5494         }
5495     },
5496
5497     // private
5498     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5499
5500     /**
5501      * Appends an event handler to this component
5502      * @param {String}   eventName The type of event to listen for
5503      * @param {Function} handler The method the event invokes
5504      * @param {Object}   scope (optional) The scope in which to execute the handler
5505      * function. The handler function's "this" context.
5506      * @param {Object}   options (optional) An object containing handler configuration
5507      * properties. This may contain any of the following properties:<ul>
5508      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5509      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5510      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5511      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5512      * by the specified number of milliseconds. If the event fires again within that time, the original
5513      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5514      * </ul><br>
5515      * <p>
5516      * <b>Combining Options</b><br>
5517      * Using the options argument, it is possible to combine different types of listeners:<br>
5518      * <br>
5519      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5520                 <pre><code>
5521                 el.on('click', this.onClick, this, {
5522                         single: true,
5523                 delay: 100,
5524                 forumId: 4
5525                 });
5526                 </code></pre>
5527      * <p>
5528      * <b>Attaching multiple handlers in 1 call</b><br>
5529      * The method also allows for a single argument to be passed which is a config object containing properties
5530      * which specify multiple handlers.
5531      * <pre><code>
5532                 el.on({
5533                         'click': {
5534                         fn: this.onClick,
5535                         scope: this,
5536                         delay: 100
5537                 }, 
5538                 'mouseover': {
5539                         fn: this.onMouseOver,
5540                         scope: this
5541                 },
5542                 'mouseout': {
5543                         fn: this.onMouseOut,
5544                         scope: this
5545                 }
5546                 });
5547                 </code></pre>
5548      * <p>
5549      * Or a shorthand syntax which passes the same scope object to all handlers:
5550         <pre><code>
5551                 el.on({
5552                         'click': this.onClick,
5553                 'mouseover': this.onMouseOver,
5554                 'mouseout': this.onMouseOut,
5555                 scope: this
5556                 });
5557                 </code></pre>
5558      */
5559     addListener : function(eventName, fn, scope, o){
5560         if(typeof eventName == "object"){
5561             o = eventName;
5562             for(var e in o){
5563                 if(this.filterOptRe.test(e)){
5564                     continue;
5565                 }
5566                 if(typeof o[e] == "function"){
5567                     // shared options
5568                     this.addListener(e, o[e], o.scope,  o);
5569                 }else{
5570                     // individual options
5571                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5572                 }
5573             }
5574             return;
5575         }
5576         o = (!o || typeof o == "boolean") ? {} : o;
5577         eventName = eventName.toLowerCase();
5578         var ce = this.events[eventName] || true;
5579         if(typeof ce == "boolean"){
5580             ce = new Roo.util.Event(this, eventName);
5581             this.events[eventName] = ce;
5582         }
5583         ce.addListener(fn, scope, o);
5584     },
5585
5586     /**
5587      * Removes a listener
5588      * @param {String}   eventName     The type of event to listen for
5589      * @param {Function} handler        The handler to remove
5590      * @param {Object}   scope  (optional) The scope (this object) for the handler
5591      */
5592     removeListener : function(eventName, fn, scope){
5593         var ce = this.events[eventName.toLowerCase()];
5594         if(typeof ce == "object"){
5595             ce.removeListener(fn, scope);
5596         }
5597     },
5598
5599     /**
5600      * Removes all listeners for this object
5601      */
5602     purgeListeners : function(){
5603         for(var evt in this.events){
5604             if(typeof this.events[evt] == "object"){
5605                  this.events[evt].clearListeners();
5606             }
5607         }
5608     },
5609
5610     relayEvents : function(o, events){
5611         var createHandler = function(ename){
5612             return function(){
5613                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5614             };
5615         };
5616         for(var i = 0, len = events.length; i < len; i++){
5617             var ename = events[i];
5618             if(!this.events[ename]){ this.events[ename] = true; };
5619             o.on(ename, createHandler(ename), this);
5620         }
5621     },
5622
5623     /**
5624      * Used to define events on this Observable
5625      * @param {Object} object The object with the events defined
5626      */
5627     addEvents : function(o){
5628         if(!this.events){
5629             this.events = {};
5630         }
5631         Roo.applyIf(this.events, o);
5632     },
5633
5634     /**
5635      * Checks to see if this object has any listeners for a specified event
5636      * @param {String} eventName The name of the event to check for
5637      * @return {Boolean} True if the event is being listened for, else false
5638      */
5639     hasListener : function(eventName){
5640         var e = this.events[eventName];
5641         return typeof e == "object" && e.listeners.length > 0;
5642     }
5643 };
5644 /**
5645  * Appends an event handler to this element (shorthand for addListener)
5646  * @param {String}   eventName     The type of event to listen for
5647  * @param {Function} handler        The method the event invokes
5648  * @param {Object}   scope (optional) The scope in which to execute the handler
5649  * function. The handler function's "this" context.
5650  * @param {Object}   options  (optional)
5651  * @method
5652  */
5653 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5654 /**
5655  * Removes a listener (shorthand for removeListener)
5656  * @param {String}   eventName     The type of event to listen for
5657  * @param {Function} handler        The handler to remove
5658  * @param {Object}   scope  (optional) The scope (this object) for the handler
5659  * @method
5660  */
5661 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5662
5663 /**
5664  * Starts capture on the specified Observable. All events will be passed
5665  * to the supplied function with the event name + standard signature of the event
5666  * <b>before</b> the event is fired. If the supplied function returns false,
5667  * the event will not fire.
5668  * @param {Observable} o The Observable to capture
5669  * @param {Function} fn The function to call
5670  * @param {Object} scope (optional) The scope (this object) for the fn
5671  * @static
5672  */
5673 Roo.util.Observable.capture = function(o, fn, scope){
5674     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5675 };
5676
5677 /**
5678  * Removes <b>all</b> added captures from the Observable.
5679  * @param {Observable} o The Observable to release
5680  * @static
5681  */
5682 Roo.util.Observable.releaseCapture = function(o){
5683     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5684 };
5685
5686 (function(){
5687
5688     var createBuffered = function(h, o, scope){
5689         var task = new Roo.util.DelayedTask();
5690         return function(){
5691             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5692         };
5693     };
5694
5695     var createSingle = function(h, e, fn, scope){
5696         return function(){
5697             e.removeListener(fn, scope);
5698             return h.apply(scope, arguments);
5699         };
5700     };
5701
5702     var createDelayed = function(h, o, scope){
5703         return function(){
5704             var args = Array.prototype.slice.call(arguments, 0);
5705             setTimeout(function(){
5706                 h.apply(scope, args);
5707             }, o.delay || 10);
5708         };
5709     };
5710
5711     Roo.util.Event = function(obj, name){
5712         this.name = name;
5713         this.obj = obj;
5714         this.listeners = [];
5715     };
5716
5717     Roo.util.Event.prototype = {
5718         addListener : function(fn, scope, options){
5719             var o = options || {};
5720             scope = scope || this.obj;
5721             if(!this.isListening(fn, scope)){
5722                 var l = {fn: fn, scope: scope, options: o};
5723                 var h = fn;
5724                 if(o.delay){
5725                     h = createDelayed(h, o, scope);
5726                 }
5727                 if(o.single){
5728                     h = createSingle(h, this, fn, scope);
5729                 }
5730                 if(o.buffer){
5731                     h = createBuffered(h, o, scope);
5732                 }
5733                 l.fireFn = h;
5734                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5735                     this.listeners.push(l);
5736                 }else{
5737                     this.listeners = this.listeners.slice(0);
5738                     this.listeners.push(l);
5739                 }
5740             }
5741         },
5742
5743         findListener : function(fn, scope){
5744             scope = scope || this.obj;
5745             var ls = this.listeners;
5746             for(var i = 0, len = ls.length; i < len; i++){
5747                 var l = ls[i];
5748                 if(l.fn == fn && l.scope == scope){
5749                     return i;
5750                 }
5751             }
5752             return -1;
5753         },
5754
5755         isListening : function(fn, scope){
5756             return this.findListener(fn, scope) != -1;
5757         },
5758
5759         removeListener : function(fn, scope){
5760             var index;
5761             if((index = this.findListener(fn, scope)) != -1){
5762                 if(!this.firing){
5763                     this.listeners.splice(index, 1);
5764                 }else{
5765                     this.listeners = this.listeners.slice(0);
5766                     this.listeners.splice(index, 1);
5767                 }
5768                 return true;
5769             }
5770             return false;
5771         },
5772
5773         clearListeners : function(){
5774             this.listeners = [];
5775         },
5776
5777         fire : function(){
5778             var ls = this.listeners, scope, len = ls.length;
5779             if(len > 0){
5780                 this.firing = true;
5781                 var args = Array.prototype.slice.call(arguments, 0);
5782                 for(var i = 0; i < len; i++){
5783                     var l = ls[i];
5784                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5785                         this.firing = false;
5786                         return false;
5787                     }
5788                 }
5789                 this.firing = false;
5790             }
5791             return true;
5792         }
5793     };
5794 })();/*
5795  * Based on:
5796  * Ext JS Library 1.1.1
5797  * Copyright(c) 2006-2007, Ext JS, LLC.
5798  *
5799  * Originally Released Under LGPL - original licence link has changed is not relivant.
5800  *
5801  * Fork - LGPL
5802  * <script type="text/javascript">
5803  */
5804
5805 /**
5806  * @class Roo.EventManager
5807  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5808  * several useful events directly.
5809  * See {@link Roo.EventObject} for more details on normalized event objects.
5810  * @singleton
5811  */
5812 Roo.EventManager = function(){
5813     var docReadyEvent, docReadyProcId, docReadyState = false;
5814     var resizeEvent, resizeTask, textEvent, textSize;
5815     var E = Roo.lib.Event;
5816     var D = Roo.lib.Dom;
5817
5818
5819     var fireDocReady = function(){
5820         if(!docReadyState){
5821             docReadyState = true;
5822             Roo.isReady = true;
5823             if(docReadyProcId){
5824                 clearInterval(docReadyProcId);
5825             }
5826             if(Roo.isGecko || Roo.isOpera) {
5827                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5828             }
5829             if(Roo.isIE){
5830                 var defer = document.getElementById("ie-deferred-loader");
5831                 if(defer){
5832                     defer.onreadystatechange = null;
5833                     defer.parentNode.removeChild(defer);
5834                 }
5835             }
5836             if(docReadyEvent){
5837                 docReadyEvent.fire();
5838                 docReadyEvent.clearListeners();
5839             }
5840         }
5841     };
5842     
5843     var initDocReady = function(){
5844         docReadyEvent = new Roo.util.Event();
5845         if(Roo.isGecko || Roo.isOpera) {
5846             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5847         }else if(Roo.isIE){
5848             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5849             var defer = document.getElementById("ie-deferred-loader");
5850             defer.onreadystatechange = function(){
5851                 if(this.readyState == "complete"){
5852                     fireDocReady();
5853                 }
5854             };
5855         }else if(Roo.isSafari){ 
5856             docReadyProcId = setInterval(function(){
5857                 var rs = document.readyState;
5858                 if(rs == "complete") {
5859                     fireDocReady();     
5860                  }
5861             }, 10);
5862         }
5863         // no matter what, make sure it fires on load
5864         E.on(window, "load", fireDocReady);
5865     };
5866
5867     var createBuffered = function(h, o){
5868         var task = new Roo.util.DelayedTask(h);
5869         return function(e){
5870             // create new event object impl so new events don't wipe out properties
5871             e = new Roo.EventObjectImpl(e);
5872             task.delay(o.buffer, h, null, [e]);
5873         };
5874     };
5875
5876     var createSingle = function(h, el, ename, fn){
5877         return function(e){
5878             Roo.EventManager.removeListener(el, ename, fn);
5879             h(e);
5880         };
5881     };
5882
5883     var createDelayed = function(h, o){
5884         return function(e){
5885             // create new event object impl so new events don't wipe out properties
5886             e = new Roo.EventObjectImpl(e);
5887             setTimeout(function(){
5888                 h(e);
5889             }, o.delay || 10);
5890         };
5891     };
5892
5893     var listen = function(element, ename, opt, fn, scope){
5894         var o = (!opt || typeof opt == "boolean") ? {} : opt;
5895         fn = fn || o.fn; scope = scope || o.scope;
5896         var el = Roo.getDom(element);
5897         if(!el){
5898             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5899         }
5900         var h = function(e){
5901             e = Roo.EventObject.setEvent(e);
5902             var t;
5903             if(o.delegate){
5904                 t = e.getTarget(o.delegate, el);
5905                 if(!t){
5906                     return;
5907                 }
5908             }else{
5909                 t = e.target;
5910             }
5911             if(o.stopEvent === true){
5912                 e.stopEvent();
5913             }
5914             if(o.preventDefault === true){
5915                e.preventDefault();
5916             }
5917             if(o.stopPropagation === true){
5918                 e.stopPropagation();
5919             }
5920
5921             if(o.normalized === false){
5922                 e = e.browserEvent;
5923             }
5924
5925             fn.call(scope || el, e, t, o);
5926         };
5927         if(o.delay){
5928             h = createDelayed(h, o);
5929         }
5930         if(o.single){
5931             h = createSingle(h, el, ename, fn);
5932         }
5933         if(o.buffer){
5934             h = createBuffered(h, o);
5935         }
5936         fn._handlers = fn._handlers || [];
5937         fn._handlers.push([Roo.id(el), ename, h]);
5938
5939         E.on(el, ename, h);
5940         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5941             el.addEventListener("DOMMouseScroll", h, false);
5942             E.on(window, 'unload', function(){
5943                 el.removeEventListener("DOMMouseScroll", h, false);
5944             });
5945         }
5946         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5947             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5948         }
5949         return h;
5950     };
5951
5952     var stopListening = function(el, ename, fn){
5953         var id = Roo.id(el), hds = fn._handlers, hd = fn;
5954         if(hds){
5955             for(var i = 0, len = hds.length; i < len; i++){
5956                 var h = hds[i];
5957                 if(h[0] == id && h[1] == ename){
5958                     hd = h[2];
5959                     hds.splice(i, 1);
5960                     break;
5961                 }
5962             }
5963         }
5964         E.un(el, ename, hd);
5965         el = Roo.getDom(el);
5966         if(ename == "mousewheel" && el.addEventListener){
5967             el.removeEventListener("DOMMouseScroll", hd, false);
5968         }
5969         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5970             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5971         }
5972     };
5973
5974     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5975     
5976     var pub = {
5977         
5978         
5979         /** 
5980          * Fix for doc tools
5981          * @scope Roo.EventManager
5982          */
5983         
5984         
5985         /** 
5986          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5987          * object with a Roo.EventObject
5988          * @param {Function} fn        The method the event invokes
5989          * @param {Object}   scope    An object that becomes the scope of the handler
5990          * @param {boolean}  override If true, the obj passed in becomes
5991          *                             the execution scope of the listener
5992          * @return {Function} The wrapped function
5993          * @deprecated
5994          */
5995         wrap : function(fn, scope, override){
5996             return function(e){
5997                 Roo.EventObject.setEvent(e);
5998                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
5999             };
6000         },
6001         
6002         /**
6003      * Appends an event handler to an element (shorthand for addListener)
6004      * @param {String/HTMLElement}   element        The html element or id to assign the
6005      * @param {String}   eventName The type of event to listen for
6006      * @param {Function} handler The method the event invokes
6007      * @param {Object}   scope (optional) The scope in which to execute the handler
6008      * function. The handler function's "this" context.
6009      * @param {Object}   options (optional) An object containing handler configuration
6010      * properties. This may contain any of the following properties:<ul>
6011      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6012      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6013      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6014      * <li>preventDefault {Boolean} True to prevent the default action</li>
6015      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6016      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6017      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6018      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6019      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6020      * by the specified number of milliseconds. If the event fires again within that time, the original
6021      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6022      * </ul><br>
6023      * <p>
6024      * <b>Combining Options</b><br>
6025      * Using the options argument, it is possible to combine different types of listeners:<br>
6026      * <br>
6027      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6028      * Code:<pre><code>
6029 el.on('click', this.onClick, this, {
6030     single: true,
6031     delay: 100,
6032     stopEvent : true,
6033     forumId: 4
6034 });</code></pre>
6035      * <p>
6036      * <b>Attaching multiple handlers in 1 call</b><br>
6037       * The method also allows for a single argument to be passed which is a config object containing properties
6038      * which specify multiple handlers.
6039      * <p>
6040      * Code:<pre><code>
6041 el.on({
6042     'click' : {
6043         fn: this.onClick
6044         scope: this,
6045         delay: 100
6046     },
6047     'mouseover' : {
6048         fn: this.onMouseOver
6049         scope: this
6050     },
6051     'mouseout' : {
6052         fn: this.onMouseOut
6053         scope: this
6054     }
6055 });</code></pre>
6056      * <p>
6057      * Or a shorthand syntax:<br>
6058      * Code:<pre><code>
6059 el.on({
6060     'click' : this.onClick,
6061     'mouseover' : this.onMouseOver,
6062     'mouseout' : this.onMouseOut
6063     scope: this
6064 });</code></pre>
6065      */
6066         addListener : function(element, eventName, fn, scope, options){
6067             if(typeof eventName == "object"){
6068                 var o = eventName;
6069                 for(var e in o){
6070                     if(propRe.test(e)){
6071                         continue;
6072                     }
6073                     if(typeof o[e] == "function"){
6074                         // shared options
6075                         listen(element, e, o, o[e], o.scope);
6076                     }else{
6077                         // individual options
6078                         listen(element, e, o[e]);
6079                     }
6080                 }
6081                 return;
6082             }
6083             return listen(element, eventName, options, fn, scope);
6084         },
6085         
6086         /**
6087          * Removes an event handler
6088          *
6089          * @param {String/HTMLElement}   element        The id or html element to remove the 
6090          *                             event from
6091          * @param {String}   eventName     The type of event
6092          * @param {Function} fn
6093          * @return {Boolean} True if a listener was actually removed
6094          */
6095         removeListener : function(element, eventName, fn){
6096             return stopListening(element, eventName, fn);
6097         },
6098         
6099         /**
6100          * Fires when the document is ready (before onload and before images are loaded). Can be 
6101          * accessed shorthanded Roo.onReady().
6102          * @param {Function} fn        The method the event invokes
6103          * @param {Object}   scope    An  object that becomes the scope of the handler
6104          * @param {boolean}  options
6105          */
6106         onDocumentReady : function(fn, scope, options){
6107             if(docReadyState){ // if it already fired
6108                 docReadyEvent.addListener(fn, scope, options);
6109                 docReadyEvent.fire();
6110                 docReadyEvent.clearListeners();
6111                 return;
6112             }
6113             if(!docReadyEvent){
6114                 initDocReady();
6115             }
6116             docReadyEvent.addListener(fn, scope, options);
6117         },
6118         
6119         /**
6120          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6121          * @param {Function} fn        The method the event invokes
6122          * @param {Object}   scope    An object that becomes the scope of the handler
6123          * @param {boolean}  options
6124          */
6125         onWindowResize : function(fn, scope, options){
6126             if(!resizeEvent){
6127                 resizeEvent = new Roo.util.Event();
6128                 resizeTask = new Roo.util.DelayedTask(function(){
6129                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6130                 });
6131                 E.on(window, "resize", function(){
6132                     if(Roo.isIE){
6133                         resizeTask.delay(50);
6134                     }else{
6135                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6136                     }
6137                 });
6138             }
6139             resizeEvent.addListener(fn, scope, options);
6140         },
6141
6142         /**
6143          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6144          * @param {Function} fn        The method the event invokes
6145          * @param {Object}   scope    An object that becomes the scope of the handler
6146          * @param {boolean}  options
6147          */
6148         onTextResize : function(fn, scope, options){
6149             if(!textEvent){
6150                 textEvent = new Roo.util.Event();
6151                 var textEl = new Roo.Element(document.createElement('div'));
6152                 textEl.dom.className = 'x-text-resize';
6153                 textEl.dom.innerHTML = 'X';
6154                 textEl.appendTo(document.body);
6155                 textSize = textEl.dom.offsetHeight;
6156                 setInterval(function(){
6157                     if(textEl.dom.offsetHeight != textSize){
6158                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6159                     }
6160                 }, this.textResizeInterval);
6161             }
6162             textEvent.addListener(fn, scope, options);
6163         },
6164
6165         /**
6166          * Removes the passed window resize listener.
6167          * @param {Function} fn        The method the event invokes
6168          * @param {Object}   scope    The scope of handler
6169          */
6170         removeResizeListener : function(fn, scope){
6171             if(resizeEvent){
6172                 resizeEvent.removeListener(fn, scope);
6173             }
6174         },
6175
6176         // private
6177         fireResize : function(){
6178             if(resizeEvent){
6179                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6180             }   
6181         },
6182         /**
6183          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6184          */
6185         ieDeferSrc : false,
6186         /**
6187          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6188          */
6189         textResizeInterval : 50
6190     };
6191     
6192     /**
6193      * Fix for doc tools
6194      * @scopeAlias pub=Roo.EventManager
6195      */
6196     
6197      /**
6198      * Appends an event handler to an element (shorthand for addListener)
6199      * @param {String/HTMLElement}   element        The html element or id to assign the
6200      * @param {String}   eventName The type of event to listen for
6201      * @param {Function} handler The method the event invokes
6202      * @param {Object}   scope (optional) The scope in which to execute the handler
6203      * function. The handler function's "this" context.
6204      * @param {Object}   options (optional) An object containing handler configuration
6205      * properties. This may contain any of the following properties:<ul>
6206      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6207      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6208      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6209      * <li>preventDefault {Boolean} True to prevent the default action</li>
6210      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6211      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6212      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6213      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6214      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6215      * by the specified number of milliseconds. If the event fires again within that time, the original
6216      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6217      * </ul><br>
6218      * <p>
6219      * <b>Combining Options</b><br>
6220      * Using the options argument, it is possible to combine different types of listeners:<br>
6221      * <br>
6222      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6223      * Code:<pre><code>
6224 el.on('click', this.onClick, this, {
6225     single: true,
6226     delay: 100,
6227     stopEvent : true,
6228     forumId: 4
6229 });</code></pre>
6230      * <p>
6231      * <b>Attaching multiple handlers in 1 call</b><br>
6232       * The method also allows for a single argument to be passed which is a config object containing properties
6233      * which specify multiple handlers.
6234      * <p>
6235      * Code:<pre><code>
6236 el.on({
6237     'click' : {
6238         fn: this.onClick
6239         scope: this,
6240         delay: 100
6241     },
6242     'mouseover' : {
6243         fn: this.onMouseOver
6244         scope: this
6245     },
6246     'mouseout' : {
6247         fn: this.onMouseOut
6248         scope: this
6249     }
6250 });</code></pre>
6251      * <p>
6252      * Or a shorthand syntax:<br>
6253      * Code:<pre><code>
6254 el.on({
6255     'click' : this.onClick,
6256     'mouseover' : this.onMouseOver,
6257     'mouseout' : this.onMouseOut
6258     scope: this
6259 });</code></pre>
6260      */
6261     pub.on = pub.addListener;
6262     pub.un = pub.removeListener;
6263
6264     pub.stoppedMouseDownEvent = new Roo.util.Event();
6265     return pub;
6266 }();
6267 /**
6268   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6269   * @param {Function} fn        The method the event invokes
6270   * @param {Object}   scope    An  object that becomes the scope of the handler
6271   * @param {boolean}  override If true, the obj passed in becomes
6272   *                             the execution scope of the listener
6273   * @member Roo
6274   * @method onReady
6275  */
6276 Roo.onReady = Roo.EventManager.onDocumentReady;
6277
6278 Roo.onReady(function(){
6279     var bd = Roo.get(document.body);
6280     if(!bd){ return; }
6281
6282     var cls = [
6283             Roo.isIE ? "roo-ie"
6284             : Roo.isGecko ? "roo-gecko"
6285             : Roo.isOpera ? "roo-opera"
6286             : Roo.isSafari ? "roo-safari" : ""];
6287
6288     if(Roo.isMac){
6289         cls.push("roo-mac");
6290     }
6291     if(Roo.isLinux){
6292         cls.push("roo-linux");
6293     }
6294     if(Roo.isBorderBox){
6295         cls.push('roo-border-box');
6296     }
6297     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6298         var p = bd.dom.parentNode;
6299         if(p){
6300             p.className += ' roo-strict';
6301         }
6302     }
6303     bd.addClass(cls.join(' '));
6304 });
6305
6306 /**
6307  * @class Roo.EventObject
6308  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6309  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6310  * Example:
6311  * <pre><code>
6312  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6313     e.preventDefault();
6314     var target = e.getTarget();
6315     ...
6316  }
6317  var myDiv = Roo.get("myDiv");
6318  myDiv.on("click", handleClick);
6319  //or
6320  Roo.EventManager.on("myDiv", 'click', handleClick);
6321  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6322  </code></pre>
6323  * @singleton
6324  */
6325 Roo.EventObject = function(){
6326     
6327     var E = Roo.lib.Event;
6328     
6329     // safari keypress events for special keys return bad keycodes
6330     var safariKeys = {
6331         63234 : 37, // left
6332         63235 : 39, // right
6333         63232 : 38, // up
6334         63233 : 40, // down
6335         63276 : 33, // page up
6336         63277 : 34, // page down
6337         63272 : 46, // delete
6338         63273 : 36, // home
6339         63275 : 35  // end
6340     };
6341
6342     // normalize button clicks
6343     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6344                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6345
6346     Roo.EventObjectImpl = function(e){
6347         if(e){
6348             this.setEvent(e.browserEvent || e);
6349         }
6350     };
6351     Roo.EventObjectImpl.prototype = {
6352         /**
6353          * Used to fix doc tools.
6354          * @scope Roo.EventObject.prototype
6355          */
6356             
6357
6358         
6359         
6360         /** The normal browser event */
6361         browserEvent : null,
6362         /** The button pressed in a mouse event */
6363         button : -1,
6364         /** True if the shift key was down during the event */
6365         shiftKey : false,
6366         /** True if the control key was down during the event */
6367         ctrlKey : false,
6368         /** True if the alt key was down during the event */
6369         altKey : false,
6370
6371         /** Key constant 
6372         * @type Number */
6373         BACKSPACE : 8,
6374         /** Key constant 
6375         * @type Number */
6376         TAB : 9,
6377         /** Key constant 
6378         * @type Number */
6379         RETURN : 13,
6380         /** Key constant 
6381         * @type Number */
6382         ENTER : 13,
6383         /** Key constant 
6384         * @type Number */
6385         SHIFT : 16,
6386         /** Key constant 
6387         * @type Number */
6388         CONTROL : 17,
6389         /** Key constant 
6390         * @type Number */
6391         ESC : 27,
6392         /** Key constant 
6393         * @type Number */
6394         SPACE : 32,
6395         /** Key constant 
6396         * @type Number */
6397         PAGEUP : 33,
6398         /** Key constant 
6399         * @type Number */
6400         PAGEDOWN : 34,
6401         /** Key constant 
6402         * @type Number */
6403         END : 35,
6404         /** Key constant 
6405         * @type Number */
6406         HOME : 36,
6407         /** Key constant 
6408         * @type Number */
6409         LEFT : 37,
6410         /** Key constant 
6411         * @type Number */
6412         UP : 38,
6413         /** Key constant 
6414         * @type Number */
6415         RIGHT : 39,
6416         /** Key constant 
6417         * @type Number */
6418         DOWN : 40,
6419         /** Key constant 
6420         * @type Number */
6421         DELETE : 46,
6422         /** Key constant 
6423         * @type Number */
6424         F5 : 116,
6425
6426            /** @private */
6427         setEvent : function(e){
6428             if(e == this || (e && e.browserEvent)){ // already wrapped
6429                 return e;
6430             }
6431             this.browserEvent = e;
6432             if(e){
6433                 // normalize buttons
6434                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6435                 if(e.type == 'click' && this.button == -1){
6436                     this.button = 0;
6437                 }
6438                 this.type = e.type;
6439                 this.shiftKey = e.shiftKey;
6440                 // mac metaKey behaves like ctrlKey
6441                 this.ctrlKey = e.ctrlKey || e.metaKey;
6442                 this.altKey = e.altKey;
6443                 // in getKey these will be normalized for the mac
6444                 this.keyCode = e.keyCode;
6445                 // keyup warnings on firefox.
6446                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6447                 // cache the target for the delayed and or buffered events
6448                 this.target = E.getTarget(e);
6449                 // same for XY
6450                 this.xy = E.getXY(e);
6451             }else{
6452                 this.button = -1;
6453                 this.shiftKey = false;
6454                 this.ctrlKey = false;
6455                 this.altKey = false;
6456                 this.keyCode = 0;
6457                 this.charCode =0;
6458                 this.target = null;
6459                 this.xy = [0, 0];
6460             }
6461             return this;
6462         },
6463
6464         /**
6465          * Stop the event (preventDefault and stopPropagation)
6466          */
6467         stopEvent : function(){
6468             if(this.browserEvent){
6469                 if(this.browserEvent.type == 'mousedown'){
6470                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6471                 }
6472                 E.stopEvent(this.browserEvent);
6473             }
6474         },
6475
6476         /**
6477          * Prevents the browsers default handling of the event.
6478          */
6479         preventDefault : function(){
6480             if(this.browserEvent){
6481                 E.preventDefault(this.browserEvent);
6482             }
6483         },
6484
6485         /** @private */
6486         isNavKeyPress : function(){
6487             var k = this.keyCode;
6488             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6489             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6490         },
6491
6492         isSpecialKey : function(){
6493             var k = this.keyCode;
6494             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6495             (k == 16) || (k == 17) ||
6496             (k >= 18 && k <= 20) ||
6497             (k >= 33 && k <= 35) ||
6498             (k >= 36 && k <= 39) ||
6499             (k >= 44 && k <= 45);
6500         },
6501         /**
6502          * Cancels bubbling of the event.
6503          */
6504         stopPropagation : function(){
6505             if(this.browserEvent){
6506                 if(this.type == 'mousedown'){
6507                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6508                 }
6509                 E.stopPropagation(this.browserEvent);
6510             }
6511         },
6512
6513         /**
6514          * Gets the key code for the event.
6515          * @return {Number}
6516          */
6517         getCharCode : function(){
6518             return this.charCode || this.keyCode;
6519         },
6520
6521         /**
6522          * Returns a normalized keyCode for the event.
6523          * @return {Number} The key code
6524          */
6525         getKey : function(){
6526             var k = this.keyCode || this.charCode;
6527             return Roo.isSafari ? (safariKeys[k] || k) : k;
6528         },
6529
6530         /**
6531          * Gets the x coordinate of the event.
6532          * @return {Number}
6533          */
6534         getPageX : function(){
6535             return this.xy[0];
6536         },
6537
6538         /**
6539          * Gets the y coordinate of the event.
6540          * @return {Number}
6541          */
6542         getPageY : function(){
6543             return this.xy[1];
6544         },
6545
6546         /**
6547          * Gets the time of the event.
6548          * @return {Number}
6549          */
6550         getTime : function(){
6551             if(this.browserEvent){
6552                 return E.getTime(this.browserEvent);
6553             }
6554             return null;
6555         },
6556
6557         /**
6558          * Gets the page coordinates of the event.
6559          * @return {Array} The xy values like [x, y]
6560          */
6561         getXY : function(){
6562             return this.xy;
6563         },
6564
6565         /**
6566          * Gets the target for the event.
6567          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6568          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6569                 search as a number or element (defaults to 10 || document.body)
6570          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6571          * @return {HTMLelement}
6572          */
6573         getTarget : function(selector, maxDepth, returnEl){
6574             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6575         },
6576         /**
6577          * Gets the related target.
6578          * @return {HTMLElement}
6579          */
6580         getRelatedTarget : function(){
6581             if(this.browserEvent){
6582                 return E.getRelatedTarget(this.browserEvent);
6583             }
6584             return null;
6585         },
6586
6587         /**
6588          * Normalizes mouse wheel delta across browsers
6589          * @return {Number} The delta
6590          */
6591         getWheelDelta : function(){
6592             var e = this.browserEvent;
6593             var delta = 0;
6594             if(e.wheelDelta){ /* IE/Opera. */
6595                 delta = e.wheelDelta/120;
6596             }else if(e.detail){ /* Mozilla case. */
6597                 delta = -e.detail/3;
6598             }
6599             return delta;
6600         },
6601
6602         /**
6603          * Returns true if the control, meta, shift or alt key was pressed during this event.
6604          * @return {Boolean}
6605          */
6606         hasModifier : function(){
6607             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6608         },
6609
6610         /**
6611          * Returns true if the target of this event equals el or is a child of el
6612          * @param {String/HTMLElement/Element} el
6613          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6614          * @return {Boolean}
6615          */
6616         within : function(el, related){
6617             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6618             return t && Roo.fly(el).contains(t);
6619         },
6620
6621         getPoint : function(){
6622             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6623         }
6624     };
6625
6626     return new Roo.EventObjectImpl();
6627 }();
6628             
6629     /*
6630  * Based on:
6631  * Ext JS Library 1.1.1
6632  * Copyright(c) 2006-2007, Ext JS, LLC.
6633  *
6634  * Originally Released Under LGPL - original licence link has changed is not relivant.
6635  *
6636  * Fork - LGPL
6637  * <script type="text/javascript">
6638  */
6639
6640  
6641 // was in Composite Element!??!?!
6642  
6643 (function(){
6644     var D = Roo.lib.Dom;
6645     var E = Roo.lib.Event;
6646     var A = Roo.lib.Anim;
6647
6648     // local style camelizing for speed
6649     var propCache = {};
6650     var camelRe = /(-[a-z])/gi;
6651     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6652     var view = document.defaultView;
6653
6654 /**
6655  * @class Roo.Element
6656  * Represents an Element in the DOM.<br><br>
6657  * Usage:<br>
6658 <pre><code>
6659 var el = Roo.get("my-div");
6660
6661 // or with getEl
6662 var el = getEl("my-div");
6663
6664 // or with a DOM element
6665 var el = Roo.get(myDivElement);
6666 </code></pre>
6667  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6668  * each call instead of constructing a new one.<br><br>
6669  * <b>Animations</b><br />
6670  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6671  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6672 <pre>
6673 Option    Default   Description
6674 --------- --------  ---------------------------------------------
6675 duration  .35       The duration of the animation in seconds
6676 easing    easeOut   The YUI easing method
6677 callback  none      A function to execute when the anim completes
6678 scope     this      The scope (this) of the callback function
6679 </pre>
6680 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6681 * manipulate the animation. Here's an example:
6682 <pre><code>
6683 var el = Roo.get("my-div");
6684
6685 // no animation
6686 el.setWidth(100);
6687
6688 // default animation
6689 el.setWidth(100, true);
6690
6691 // animation with some options set
6692 el.setWidth(100, {
6693     duration: 1,
6694     callback: this.foo,
6695     scope: this
6696 });
6697
6698 // using the "anim" property to get the Anim object
6699 var opt = {
6700     duration: 1,
6701     callback: this.foo,
6702     scope: this
6703 };
6704 el.setWidth(100, opt);
6705 ...
6706 if(opt.anim.isAnimated()){
6707     opt.anim.stop();
6708 }
6709 </code></pre>
6710 * <b> Composite (Collections of) Elements</b><br />
6711  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6712  * @constructor Create a new Element directly.
6713  * @param {String/HTMLElement} element
6714  * @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).
6715  */
6716     Roo.Element = function(element, forceNew){
6717         var dom = typeof element == "string" ?
6718                 document.getElementById(element) : element;
6719         if(!dom){ // invalid id/element
6720             return null;
6721         }
6722         var id = dom.id;
6723         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6724             return Roo.Element.cache[id];
6725         }
6726
6727         /**
6728          * The DOM element
6729          * @type HTMLElement
6730          */
6731         this.dom = dom;
6732
6733         /**
6734          * The DOM element ID
6735          * @type String
6736          */
6737         this.id = id || Roo.id(dom);
6738     };
6739
6740     var El = Roo.Element;
6741
6742     El.prototype = {
6743         /**
6744          * The element's default display mode  (defaults to "")
6745          * @type String
6746          */
6747         originalDisplay : "",
6748
6749         visibilityMode : 1,
6750         /**
6751          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6752          * @type String
6753          */
6754         defaultUnit : "px",
6755         /**
6756          * Sets the element's visibility mode. When setVisible() is called it
6757          * will use this to determine whether to set the visibility or the display property.
6758          * @param visMode Element.VISIBILITY or Element.DISPLAY
6759          * @return {Roo.Element} this
6760          */
6761         setVisibilityMode : function(visMode){
6762             this.visibilityMode = visMode;
6763             return this;
6764         },
6765         /**
6766          * Convenience method for setVisibilityMode(Element.DISPLAY)
6767          * @param {String} display (optional) What to set display to when visible
6768          * @return {Roo.Element} this
6769          */
6770         enableDisplayMode : function(display){
6771             this.setVisibilityMode(El.DISPLAY);
6772             if(typeof display != "undefined") this.originalDisplay = display;
6773             return this;
6774         },
6775
6776         /**
6777          * 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)
6778          * @param {String} selector The simple selector to test
6779          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6780                 search as a number or element (defaults to 10 || document.body)
6781          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6782          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6783          */
6784         findParent : function(simpleSelector, maxDepth, returnEl){
6785             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6786             maxDepth = maxDepth || 50;
6787             if(typeof maxDepth != "number"){
6788                 stopEl = Roo.getDom(maxDepth);
6789                 maxDepth = 10;
6790             }
6791             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6792                 if(dq.is(p, simpleSelector)){
6793                     return returnEl ? Roo.get(p) : p;
6794                 }
6795                 depth++;
6796                 p = p.parentNode;
6797             }
6798             return null;
6799         },
6800
6801
6802         /**
6803          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6804          * @param {String} selector The simple selector to test
6805          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6806                 search as a number or element (defaults to 10 || document.body)
6807          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6808          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6809          */
6810         findParentNode : function(simpleSelector, maxDepth, returnEl){
6811             var p = Roo.fly(this.dom.parentNode, '_internal');
6812             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6813         },
6814
6815         /**
6816          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6817          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6818          * @param {String} selector The simple selector to test
6819          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6820                 search as a number or element (defaults to 10 || document.body)
6821          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6822          */
6823         up : function(simpleSelector, maxDepth){
6824             return this.findParentNode(simpleSelector, maxDepth, true);
6825         },
6826
6827
6828
6829         /**
6830          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6831          * @param {String} selector The simple selector to test
6832          * @return {Boolean} True if this element matches the selector, else false
6833          */
6834         is : function(simpleSelector){
6835             return Roo.DomQuery.is(this.dom, simpleSelector);
6836         },
6837
6838         /**
6839          * Perform animation on this element.
6840          * @param {Object} args The YUI animation control args
6841          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6842          * @param {Function} onComplete (optional) Function to call when animation completes
6843          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6844          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6845          * @return {Roo.Element} this
6846          */
6847         animate : function(args, duration, onComplete, easing, animType){
6848             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6849             return this;
6850         },
6851
6852         /*
6853          * @private Internal animation call
6854          */
6855         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6856             animType = animType || 'run';
6857             opt = opt || {};
6858             var anim = Roo.lib.Anim[animType](
6859                 this.dom, args,
6860                 (opt.duration || defaultDur) || .35,
6861                 (opt.easing || defaultEase) || 'easeOut',
6862                 function(){
6863                     Roo.callback(cb, this);
6864                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6865                 },
6866                 this
6867             );
6868             opt.anim = anim;
6869             return anim;
6870         },
6871
6872         // private legacy anim prep
6873         preanim : function(a, i){
6874             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6875         },
6876
6877         /**
6878          * Removes worthless text nodes
6879          * @param {Boolean} forceReclean (optional) By default the element
6880          * keeps track if it has been cleaned already so
6881          * you can call this over and over. However, if you update the element and
6882          * need to force a reclean, you can pass true.
6883          */
6884         clean : function(forceReclean){
6885             if(this.isCleaned && forceReclean !== true){
6886                 return this;
6887             }
6888             var ns = /\S/;
6889             var d = this.dom, n = d.firstChild, ni = -1;
6890             while(n){
6891                 var nx = n.nextSibling;
6892                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6893                     d.removeChild(n);
6894                 }else{
6895                     n.nodeIndex = ++ni;
6896                 }
6897                 n = nx;
6898             }
6899             this.isCleaned = true;
6900             return this;
6901         },
6902
6903         // private
6904         calcOffsetsTo : function(el){
6905             el = Roo.get(el);
6906             var d = el.dom;
6907             var restorePos = false;
6908             if(el.getStyle('position') == 'static'){
6909                 el.position('relative');
6910                 restorePos = true;
6911             }
6912             var x = 0, y =0;
6913             var op = this.dom;
6914             while(op && op != d && op.tagName != 'HTML'){
6915                 x+= op.offsetLeft;
6916                 y+= op.offsetTop;
6917                 op = op.offsetParent;
6918             }
6919             if(restorePos){
6920                 el.position('static');
6921             }
6922             return [x, y];
6923         },
6924
6925         /**
6926          * Scrolls this element into view within the passed container.
6927          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6928          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6929          * @return {Roo.Element} this
6930          */
6931         scrollIntoView : function(container, hscroll){
6932             var c = Roo.getDom(container) || document.body;
6933             var el = this.dom;
6934
6935             var o = this.calcOffsetsTo(c),
6936                 l = o[0],
6937                 t = o[1],
6938                 b = t+el.offsetHeight,
6939                 r = l+el.offsetWidth;
6940
6941             var ch = c.clientHeight;
6942             var ct = parseInt(c.scrollTop, 10);
6943             var cl = parseInt(c.scrollLeft, 10);
6944             var cb = ct + ch;
6945             var cr = cl + c.clientWidth;
6946
6947             if(t < ct){
6948                 c.scrollTop = t;
6949             }else if(b > cb){
6950                 c.scrollTop = b-ch;
6951             }
6952
6953             if(hscroll !== false){
6954                 if(l < cl){
6955                     c.scrollLeft = l;
6956                 }else if(r > cr){
6957                     c.scrollLeft = r-c.clientWidth;
6958                 }
6959             }
6960             return this;
6961         },
6962
6963         // private
6964         scrollChildIntoView : function(child, hscroll){
6965             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6966         },
6967
6968         /**
6969          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6970          * the new height may not be available immediately.
6971          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6972          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6973          * @param {Function} onComplete (optional) Function to call when animation completes
6974          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6975          * @return {Roo.Element} this
6976          */
6977         autoHeight : function(animate, duration, onComplete, easing){
6978             var oldHeight = this.getHeight();
6979             this.clip();
6980             this.setHeight(1); // force clipping
6981             setTimeout(function(){
6982                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6983                 if(!animate){
6984                     this.setHeight(height);
6985                     this.unclip();
6986                     if(typeof onComplete == "function"){
6987                         onComplete();
6988                     }
6989                 }else{
6990                     this.setHeight(oldHeight); // restore original height
6991                     this.setHeight(height, animate, duration, function(){
6992                         this.unclip();
6993                         if(typeof onComplete == "function") onComplete();
6994                     }.createDelegate(this), easing);
6995                 }
6996             }.createDelegate(this), 0);
6997             return this;
6998         },
6999
7000         /**
7001          * Returns true if this element is an ancestor of the passed element
7002          * @param {HTMLElement/String} el The element to check
7003          * @return {Boolean} True if this element is an ancestor of el, else false
7004          */
7005         contains : function(el){
7006             if(!el){return false;}
7007             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7008         },
7009
7010         /**
7011          * Checks whether the element is currently visible using both visibility and display properties.
7012          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7013          * @return {Boolean} True if the element is currently visible, else false
7014          */
7015         isVisible : function(deep) {
7016             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7017             if(deep !== true || !vis){
7018                 return vis;
7019             }
7020             var p = this.dom.parentNode;
7021             while(p && p.tagName.toLowerCase() != "body"){
7022                 if(!Roo.fly(p, '_isVisible').isVisible()){
7023                     return false;
7024                 }
7025                 p = p.parentNode;
7026             }
7027             return true;
7028         },
7029
7030         /**
7031          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7032          * @param {String} selector The CSS selector
7033          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7034          * @return {CompositeElement/CompositeElementLite} The composite element
7035          */
7036         select : function(selector, unique){
7037             return El.select(selector, unique, this.dom);
7038         },
7039
7040         /**
7041          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7042          * @param {String} selector The CSS selector
7043          * @return {Array} An array of the matched nodes
7044          */
7045         query : function(selector, unique){
7046             return Roo.DomQuery.select(selector, this.dom);
7047         },
7048
7049         /**
7050          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7051          * @param {String} selector The CSS selector
7052          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7053          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7054          */
7055         child : function(selector, returnDom){
7056             var n = Roo.DomQuery.selectNode(selector, this.dom);
7057             return returnDom ? n : Roo.get(n);
7058         },
7059
7060         /**
7061          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7062          * @param {String} selector The CSS selector
7063          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7064          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7065          */
7066         down : function(selector, returnDom){
7067             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7068             return returnDom ? n : Roo.get(n);
7069         },
7070
7071         /**
7072          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7073          * @param {String} group The group the DD object is member of
7074          * @param {Object} config The DD config object
7075          * @param {Object} overrides An object containing methods to override/implement on the DD object
7076          * @return {Roo.dd.DD} The DD object
7077          */
7078         initDD : function(group, config, overrides){
7079             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7080             return Roo.apply(dd, overrides);
7081         },
7082
7083         /**
7084          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7085          * @param {String} group The group the DDProxy object is member of
7086          * @param {Object} config The DDProxy config object
7087          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7088          * @return {Roo.dd.DDProxy} The DDProxy object
7089          */
7090         initDDProxy : function(group, config, overrides){
7091             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7092             return Roo.apply(dd, overrides);
7093         },
7094
7095         /**
7096          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7097          * @param {String} group The group the DDTarget object is member of
7098          * @param {Object} config The DDTarget config object
7099          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7100          * @return {Roo.dd.DDTarget} The DDTarget object
7101          */
7102         initDDTarget : function(group, config, overrides){
7103             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7104             return Roo.apply(dd, overrides);
7105         },
7106
7107         /**
7108          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7109          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7110          * @param {Boolean} visible Whether the element is visible
7111          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7112          * @return {Roo.Element} this
7113          */
7114          setVisible : function(visible, animate){
7115             if(!animate || !A){
7116                 if(this.visibilityMode == El.DISPLAY){
7117                     this.setDisplayed(visible);
7118                 }else{
7119                     this.fixDisplay();
7120                     this.dom.style.visibility = visible ? "visible" : "hidden";
7121                 }
7122             }else{
7123                 // closure for composites
7124                 var dom = this.dom;
7125                 var visMode = this.visibilityMode;
7126                 if(visible){
7127                     this.setOpacity(.01);
7128                     this.setVisible(true);
7129                 }
7130                 this.anim({opacity: { to: (visible?1:0) }},
7131                       this.preanim(arguments, 1),
7132                       null, .35, 'easeIn', function(){
7133                          if(!visible){
7134                              if(visMode == El.DISPLAY){
7135                                  dom.style.display = "none";
7136                              }else{
7137                                  dom.style.visibility = "hidden";
7138                              }
7139                              Roo.get(dom).setOpacity(1);
7140                          }
7141                      });
7142             }
7143             return this;
7144         },
7145
7146         /**
7147          * Returns true if display is not "none"
7148          * @return {Boolean}
7149          */
7150         isDisplayed : function() {
7151             return this.getStyle("display") != "none";
7152         },
7153
7154         /**
7155          * Toggles the element's visibility or display, depending on visibility mode.
7156          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7157          * @return {Roo.Element} this
7158          */
7159         toggle : function(animate){
7160             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7161             return this;
7162         },
7163
7164         /**
7165          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7166          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7167          * @return {Roo.Element} this
7168          */
7169         setDisplayed : function(value) {
7170             if(typeof value == "boolean"){
7171                value = value ? this.originalDisplay : "none";
7172             }
7173             this.setStyle("display", value);
7174             return this;
7175         },
7176
7177         /**
7178          * Tries to focus the element. Any exceptions are caught and ignored.
7179          * @return {Roo.Element} this
7180          */
7181         focus : function() {
7182             try{
7183                 this.dom.focus();
7184             }catch(e){}
7185             return this;
7186         },
7187
7188         /**
7189          * Tries to blur the element. Any exceptions are caught and ignored.
7190          * @return {Roo.Element} this
7191          */
7192         blur : function() {
7193             try{
7194                 this.dom.blur();
7195             }catch(e){}
7196             return this;
7197         },
7198
7199         /**
7200          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7201          * @param {String/Array} className The CSS class to add, or an array of classes
7202          * @return {Roo.Element} this
7203          */
7204         addClass : function(className){
7205             if(className instanceof Array){
7206                 for(var i = 0, len = className.length; i < len; i++) {
7207                     this.addClass(className[i]);
7208                 }
7209             }else{
7210                 if(className && !this.hasClass(className)){
7211                     this.dom.className = this.dom.className + " " + className;
7212                 }
7213             }
7214             return this;
7215         },
7216
7217         /**
7218          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7219          * @param {String/Array} className The CSS class to add, or an array of classes
7220          * @return {Roo.Element} this
7221          */
7222         radioClass : function(className){
7223             var siblings = this.dom.parentNode.childNodes;
7224             for(var i = 0; i < siblings.length; i++) {
7225                 var s = siblings[i];
7226                 if(s.nodeType == 1){
7227                     Roo.get(s).removeClass(className);
7228                 }
7229             }
7230             this.addClass(className);
7231             return this;
7232         },
7233
7234         /**
7235          * Removes one or more CSS classes from the element.
7236          * @param {String/Array} className The CSS class to remove, or an array of classes
7237          * @return {Roo.Element} this
7238          */
7239         removeClass : function(className){
7240             if(!className || !this.dom.className){
7241                 return this;
7242             }
7243             if(className instanceof Array){
7244                 for(var i = 0, len = className.length; i < len; i++) {
7245                     this.removeClass(className[i]);
7246                 }
7247             }else{
7248                 if(this.hasClass(className)){
7249                     var re = this.classReCache[className];
7250                     if (!re) {
7251                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7252                        this.classReCache[className] = re;
7253                     }
7254                     this.dom.className =
7255                         this.dom.className.replace(re, " ");
7256                 }
7257             }
7258             return this;
7259         },
7260
7261         // private
7262         classReCache: {},
7263
7264         /**
7265          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7266          * @param {String} className The CSS class to toggle
7267          * @return {Roo.Element} this
7268          */
7269         toggleClass : function(className){
7270             if(this.hasClass(className)){
7271                 this.removeClass(className);
7272             }else{
7273                 this.addClass(className);
7274             }
7275             return this;
7276         },
7277
7278         /**
7279          * Checks if the specified CSS class exists on this element's DOM node.
7280          * @param {String} className The CSS class to check for
7281          * @return {Boolean} True if the class exists, else false
7282          */
7283         hasClass : function(className){
7284             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7285         },
7286
7287         /**
7288          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7289          * @param {String} oldClassName The CSS class to replace
7290          * @param {String} newClassName The replacement CSS class
7291          * @return {Roo.Element} this
7292          */
7293         replaceClass : function(oldClassName, newClassName){
7294             this.removeClass(oldClassName);
7295             this.addClass(newClassName);
7296             return this;
7297         },
7298
7299         /**
7300          * Returns an object with properties matching the styles requested.
7301          * For example, el.getStyles('color', 'font-size', 'width') might return
7302          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7303          * @param {String} style1 A style name
7304          * @param {String} style2 A style name
7305          * @param {String} etc.
7306          * @return {Object} The style object
7307          */
7308         getStyles : function(){
7309             var a = arguments, len = a.length, r = {};
7310             for(var i = 0; i < len; i++){
7311                 r[a[i]] = this.getStyle(a[i]);
7312             }
7313             return r;
7314         },
7315
7316         /**
7317          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7318          * @param {String} property The style property whose value is returned.
7319          * @return {String} The current value of the style property for this element.
7320          */
7321         getStyle : function(){
7322             return view && view.getComputedStyle ?
7323                 function(prop){
7324                     var el = this.dom, v, cs, camel;
7325                     if(prop == 'float'){
7326                         prop = "cssFloat";
7327                     }
7328                     if(el.style && (v = el.style[prop])){
7329                         return v;
7330                     }
7331                     if(cs = view.getComputedStyle(el, "")){
7332                         if(!(camel = propCache[prop])){
7333                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7334                         }
7335                         return cs[camel];
7336                     }
7337                     return null;
7338                 } :
7339                 function(prop){
7340                     var el = this.dom, v, cs, camel;
7341                     if(prop == 'opacity'){
7342                         if(typeof el.style.filter == 'string'){
7343                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7344                             if(m){
7345                                 var fv = parseFloat(m[1]);
7346                                 if(!isNaN(fv)){
7347                                     return fv ? fv / 100 : 0;
7348                                 }
7349                             }
7350                         }
7351                         return 1;
7352                     }else if(prop == 'float'){
7353                         prop = "styleFloat";
7354                     }
7355                     if(!(camel = propCache[prop])){
7356                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7357                     }
7358                     if(v = el.style[camel]){
7359                         return v;
7360                     }
7361                     if(cs = el.currentStyle){
7362                         return cs[camel];
7363                     }
7364                     return null;
7365                 };
7366         }(),
7367
7368         /**
7369          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7370          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7371          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7372          * @return {Roo.Element} this
7373          */
7374         setStyle : function(prop, value){
7375             if(typeof prop == "string"){
7376                 
7377                 if (prop == 'float') {
7378                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7379                     return this;
7380                 }
7381                 
7382                 var camel;
7383                 if(!(camel = propCache[prop])){
7384                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7385                 }
7386                 
7387                 if(camel == 'opacity') {
7388                     this.setOpacity(value);
7389                 }else{
7390                     this.dom.style[camel] = value;
7391                 }
7392             }else{
7393                 for(var style in prop){
7394                     if(typeof prop[style] != "function"){
7395                        this.setStyle(style, prop[style]);
7396                     }
7397                 }
7398             }
7399             return this;
7400         },
7401
7402         /**
7403          * More flexible version of {@link #setStyle} for setting style properties.
7404          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7405          * a function which returns such a specification.
7406          * @return {Roo.Element} this
7407          */
7408         applyStyles : function(style){
7409             Roo.DomHelper.applyStyles(this.dom, style);
7410             return this;
7411         },
7412
7413         /**
7414           * 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).
7415           * @return {Number} The X position of the element
7416           */
7417         getX : function(){
7418             return D.getX(this.dom);
7419         },
7420
7421         /**
7422           * 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).
7423           * @return {Number} The Y position of the element
7424           */
7425         getY : function(){
7426             return D.getY(this.dom);
7427         },
7428
7429         /**
7430           * 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).
7431           * @return {Array} The XY position of the element
7432           */
7433         getXY : function(){
7434             return D.getXY(this.dom);
7435         },
7436
7437         /**
7438          * 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).
7439          * @param {Number} The X position of the element
7440          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7441          * @return {Roo.Element} this
7442          */
7443         setX : function(x, animate){
7444             if(!animate || !A){
7445                 D.setX(this.dom, x);
7446             }else{
7447                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7448             }
7449             return this;
7450         },
7451
7452         /**
7453          * 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).
7454          * @param {Number} The Y position of the element
7455          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7456          * @return {Roo.Element} this
7457          */
7458         setY : function(y, animate){
7459             if(!animate || !A){
7460                 D.setY(this.dom, y);
7461             }else{
7462                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7463             }
7464             return this;
7465         },
7466
7467         /**
7468          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7469          * @param {String} left The left CSS property value
7470          * @return {Roo.Element} this
7471          */
7472         setLeft : function(left){
7473             this.setStyle("left", this.addUnits(left));
7474             return this;
7475         },
7476
7477         /**
7478          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7479          * @param {String} top The top CSS property value
7480          * @return {Roo.Element} this
7481          */
7482         setTop : function(top){
7483             this.setStyle("top", this.addUnits(top));
7484             return this;
7485         },
7486
7487         /**
7488          * Sets the element's CSS right style.
7489          * @param {String} right The right CSS property value
7490          * @return {Roo.Element} this
7491          */
7492         setRight : function(right){
7493             this.setStyle("right", this.addUnits(right));
7494             return this;
7495         },
7496
7497         /**
7498          * Sets the element's CSS bottom style.
7499          * @param {String} bottom The bottom CSS property value
7500          * @return {Roo.Element} this
7501          */
7502         setBottom : function(bottom){
7503             this.setStyle("bottom", this.addUnits(bottom));
7504             return this;
7505         },
7506
7507         /**
7508          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7509          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7510          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7511          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7512          * @return {Roo.Element} this
7513          */
7514         setXY : function(pos, animate){
7515             if(!animate || !A){
7516                 D.setXY(this.dom, pos);
7517             }else{
7518                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7519             }
7520             return this;
7521         },
7522
7523         /**
7524          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7525          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7526          * @param {Number} x X value for new position (coordinates are page-based)
7527          * @param {Number} y Y value for new position (coordinates are page-based)
7528          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7529          * @return {Roo.Element} this
7530          */
7531         setLocation : function(x, y, animate){
7532             this.setXY([x, y], this.preanim(arguments, 2));
7533             return this;
7534         },
7535
7536         /**
7537          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7538          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7539          * @param {Number} x X value for new position (coordinates are page-based)
7540          * @param {Number} y Y value for new position (coordinates are page-based)
7541          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7542          * @return {Roo.Element} this
7543          */
7544         moveTo : function(x, y, animate){
7545             this.setXY([x, y], this.preanim(arguments, 2));
7546             return this;
7547         },
7548
7549         /**
7550          * Returns the region of the given element.
7551          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7552          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7553          */
7554         getRegion : function(){
7555             return D.getRegion(this.dom);
7556         },
7557
7558         /**
7559          * Returns the offset height of the element
7560          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7561          * @return {Number} The element's height
7562          */
7563         getHeight : function(contentHeight){
7564             var h = this.dom.offsetHeight || 0;
7565             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7566         },
7567
7568         /**
7569          * Returns the offset width of the element
7570          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7571          * @return {Number} The element's width
7572          */
7573         getWidth : function(contentWidth){
7574             var w = this.dom.offsetWidth || 0;
7575             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7576         },
7577
7578         /**
7579          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7580          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7581          * if a height has not been set using CSS.
7582          * @return {Number}
7583          */
7584         getComputedHeight : function(){
7585             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7586             if(!h){
7587                 h = parseInt(this.getStyle('height'), 10) || 0;
7588                 if(!this.isBorderBox()){
7589                     h += this.getFrameWidth('tb');
7590                 }
7591             }
7592             return h;
7593         },
7594
7595         /**
7596          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7597          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7598          * if a width has not been set using CSS.
7599          * @return {Number}
7600          */
7601         getComputedWidth : function(){
7602             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7603             if(!w){
7604                 w = parseInt(this.getStyle('width'), 10) || 0;
7605                 if(!this.isBorderBox()){
7606                     w += this.getFrameWidth('lr');
7607                 }
7608             }
7609             return w;
7610         },
7611
7612         /**
7613          * Returns the size of the element.
7614          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7615          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7616          */
7617         getSize : function(contentSize){
7618             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7619         },
7620
7621         /**
7622          * Returns the width and height of the viewport.
7623          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7624          */
7625         getViewSize : function(){
7626             var d = this.dom, doc = document, aw = 0, ah = 0;
7627             if(d == doc || d == doc.body){
7628                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7629             }else{
7630                 return {
7631                     width : d.clientWidth,
7632                     height: d.clientHeight
7633                 };
7634             }
7635         },
7636
7637         /**
7638          * Returns the value of the "value" attribute
7639          * @param {Boolean} asNumber true to parse the value as a number
7640          * @return {String/Number}
7641          */
7642         getValue : function(asNumber){
7643             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7644         },
7645
7646         // private
7647         adjustWidth : function(width){
7648             if(typeof width == "number"){
7649                 if(this.autoBoxAdjust && !this.isBorderBox()){
7650                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7651                 }
7652                 if(width < 0){
7653                     width = 0;
7654                 }
7655             }
7656             return width;
7657         },
7658
7659         // private
7660         adjustHeight : function(height){
7661             if(typeof height == "number"){
7662                if(this.autoBoxAdjust && !this.isBorderBox()){
7663                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7664                }
7665                if(height < 0){
7666                    height = 0;
7667                }
7668             }
7669             return height;
7670         },
7671
7672         /**
7673          * Set the width of the element
7674          * @param {Number} width The new width
7675          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7676          * @return {Roo.Element} this
7677          */
7678         setWidth : function(width, animate){
7679             width = this.adjustWidth(width);
7680             if(!animate || !A){
7681                 this.dom.style.width = this.addUnits(width);
7682             }else{
7683                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7684             }
7685             return this;
7686         },
7687
7688         /**
7689          * Set the height of the element
7690          * @param {Number} height The new height
7691          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7692          * @return {Roo.Element} this
7693          */
7694          setHeight : function(height, animate){
7695             height = this.adjustHeight(height);
7696             if(!animate || !A){
7697                 this.dom.style.height = this.addUnits(height);
7698             }else{
7699                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7700             }
7701             return this;
7702         },
7703
7704         /**
7705          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7706          * @param {Number} width The new width
7707          * @param {Number} height The new height
7708          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7709          * @return {Roo.Element} this
7710          */
7711          setSize : function(width, height, animate){
7712             if(typeof width == "object"){ // in case of object from getSize()
7713                 height = width.height; width = width.width;
7714             }
7715             width = this.adjustWidth(width); height = this.adjustHeight(height);
7716             if(!animate || !A){
7717                 this.dom.style.width = this.addUnits(width);
7718                 this.dom.style.height = this.addUnits(height);
7719             }else{
7720                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7721             }
7722             return this;
7723         },
7724
7725         /**
7726          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7727          * @param {Number} x X value for new position (coordinates are page-based)
7728          * @param {Number} y Y value for new position (coordinates are page-based)
7729          * @param {Number} width The new width
7730          * @param {Number} height The new height
7731          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7732          * @return {Roo.Element} this
7733          */
7734         setBounds : function(x, y, width, height, animate){
7735             if(!animate || !A){
7736                 this.setSize(width, height);
7737                 this.setLocation(x, y);
7738             }else{
7739                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7740                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7741                               this.preanim(arguments, 4), 'motion');
7742             }
7743             return this;
7744         },
7745
7746         /**
7747          * 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.
7748          * @param {Roo.lib.Region} region The region to fill
7749          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7750          * @return {Roo.Element} this
7751          */
7752         setRegion : function(region, animate){
7753             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7754             return this;
7755         },
7756
7757         /**
7758          * Appends an event handler
7759          *
7760          * @param {String}   eventName     The type of event to append
7761          * @param {Function} fn        The method the event invokes
7762          * @param {Object} scope       (optional) The scope (this object) of the fn
7763          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7764          */
7765         addListener : function(eventName, fn, scope, options){
7766             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7767         },
7768
7769         /**
7770          * Removes an event handler from this element
7771          * @param {String} eventName the type of event to remove
7772          * @param {Function} fn the method the event invokes
7773          * @return {Roo.Element} this
7774          */
7775         removeListener : function(eventName, fn){
7776             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7777             return this;
7778         },
7779
7780         /**
7781          * Removes all previous added listeners from this element
7782          * @return {Roo.Element} this
7783          */
7784         removeAllListeners : function(){
7785             E.purgeElement(this.dom);
7786             return this;
7787         },
7788
7789         relayEvent : function(eventName, observable){
7790             this.on(eventName, function(e){
7791                 observable.fireEvent(eventName, e);
7792             });
7793         },
7794
7795         /**
7796          * Set the opacity of the element
7797          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7798          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7799          * @return {Roo.Element} this
7800          */
7801          setOpacity : function(opacity, animate){
7802             if(!animate || !A){
7803                 var s = this.dom.style;
7804                 if(Roo.isIE){
7805                     s.zoom = 1;
7806                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7807                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7808                 }else{
7809                     s.opacity = opacity;
7810                 }
7811             }else{
7812                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7813             }
7814             return this;
7815         },
7816
7817         /**
7818          * Gets the left X coordinate
7819          * @param {Boolean} local True to get the local css position instead of page coordinate
7820          * @return {Number}
7821          */
7822         getLeft : function(local){
7823             if(!local){
7824                 return this.getX();
7825             }else{
7826                 return parseInt(this.getStyle("left"), 10) || 0;
7827             }
7828         },
7829
7830         /**
7831          * Gets the right X coordinate of the element (element X position + element width)
7832          * @param {Boolean} local True to get the local css position instead of page coordinate
7833          * @return {Number}
7834          */
7835         getRight : function(local){
7836             if(!local){
7837                 return this.getX() + this.getWidth();
7838             }else{
7839                 return (this.getLeft(true) + this.getWidth()) || 0;
7840             }
7841         },
7842
7843         /**
7844          * Gets the top Y coordinate
7845          * @param {Boolean} local True to get the local css position instead of page coordinate
7846          * @return {Number}
7847          */
7848         getTop : function(local) {
7849             if(!local){
7850                 return this.getY();
7851             }else{
7852                 return parseInt(this.getStyle("top"), 10) || 0;
7853             }
7854         },
7855
7856         /**
7857          * Gets the bottom Y coordinate of the element (element Y position + element height)
7858          * @param {Boolean} local True to get the local css position instead of page coordinate
7859          * @return {Number}
7860          */
7861         getBottom : function(local){
7862             if(!local){
7863                 return this.getY() + this.getHeight();
7864             }else{
7865                 return (this.getTop(true) + this.getHeight()) || 0;
7866             }
7867         },
7868
7869         /**
7870         * Initializes positioning on this element. If a desired position is not passed, it will make the
7871         * the element positioned relative IF it is not already positioned.
7872         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7873         * @param {Number} zIndex (optional) The zIndex to apply
7874         * @param {Number} x (optional) Set the page X position
7875         * @param {Number} y (optional) Set the page Y position
7876         */
7877         position : function(pos, zIndex, x, y){
7878             if(!pos){
7879                if(this.getStyle('position') == 'static'){
7880                    this.setStyle('position', 'relative');
7881                }
7882             }else{
7883                 this.setStyle("position", pos);
7884             }
7885             if(zIndex){
7886                 this.setStyle("z-index", zIndex);
7887             }
7888             if(x !== undefined && y !== undefined){
7889                 this.setXY([x, y]);
7890             }else if(x !== undefined){
7891                 this.setX(x);
7892             }else if(y !== undefined){
7893                 this.setY(y);
7894             }
7895         },
7896
7897         /**
7898         * Clear positioning back to the default when the document was loaded
7899         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7900         * @return {Roo.Element} this
7901          */
7902         clearPositioning : function(value){
7903             value = value ||'';
7904             this.setStyle({
7905                 "left": value,
7906                 "right": value,
7907                 "top": value,
7908                 "bottom": value,
7909                 "z-index": "",
7910                 "position" : "static"
7911             });
7912             return this;
7913         },
7914
7915         /**
7916         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7917         * snapshot before performing an update and then restoring the element.
7918         * @return {Object}
7919         */
7920         getPositioning : function(){
7921             var l = this.getStyle("left");
7922             var t = this.getStyle("top");
7923             return {
7924                 "position" : this.getStyle("position"),
7925                 "left" : l,
7926                 "right" : l ? "" : this.getStyle("right"),
7927                 "top" : t,
7928                 "bottom" : t ? "" : this.getStyle("bottom"),
7929                 "z-index" : this.getStyle("z-index")
7930             };
7931         },
7932
7933         /**
7934          * Gets the width of the border(s) for the specified side(s)
7935          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7936          * passing lr would get the border (l)eft width + the border (r)ight width.
7937          * @return {Number} The width of the sides passed added together
7938          */
7939         getBorderWidth : function(side){
7940             return this.addStyles(side, El.borders);
7941         },
7942
7943         /**
7944          * Gets the width of the padding(s) for the specified side(s)
7945          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7946          * passing lr would get the padding (l)eft + the padding (r)ight.
7947          * @return {Number} The padding of the sides passed added together
7948          */
7949         getPadding : function(side){
7950             return this.addStyles(side, El.paddings);
7951         },
7952
7953         /**
7954         * Set positioning with an object returned by getPositioning().
7955         * @param {Object} posCfg
7956         * @return {Roo.Element} this
7957          */
7958         setPositioning : function(pc){
7959             this.applyStyles(pc);
7960             if(pc.right == "auto"){
7961                 this.dom.style.right = "";
7962             }
7963             if(pc.bottom == "auto"){
7964                 this.dom.style.bottom = "";
7965             }
7966             return this;
7967         },
7968
7969         // private
7970         fixDisplay : function(){
7971             if(this.getStyle("display") == "none"){
7972                 this.setStyle("visibility", "hidden");
7973                 this.setStyle("display", this.originalDisplay); // first try reverting to default
7974                 if(this.getStyle("display") == "none"){ // if that fails, default to block
7975                     this.setStyle("display", "block");
7976                 }
7977             }
7978         },
7979
7980         /**
7981          * Quick set left and top adding default units
7982          * @param {String} left The left CSS property value
7983          * @param {String} top The top CSS property value
7984          * @return {Roo.Element} this
7985          */
7986          setLeftTop : function(left, top){
7987             this.dom.style.left = this.addUnits(left);
7988             this.dom.style.top = this.addUnits(top);
7989             return this;
7990         },
7991
7992         /**
7993          * Move this element relative to its current position.
7994          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7995          * @param {Number} distance How far to move the element in pixels
7996          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7997          * @return {Roo.Element} this
7998          */
7999          move : function(direction, distance, animate){
8000             var xy = this.getXY();
8001             direction = direction.toLowerCase();
8002             switch(direction){
8003                 case "l":
8004                 case "left":
8005                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8006                     break;
8007                case "r":
8008                case "right":
8009                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8010                     break;
8011                case "t":
8012                case "top":
8013                case "up":
8014                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8015                     break;
8016                case "b":
8017                case "bottom":
8018                case "down":
8019                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8020                     break;
8021             }
8022             return this;
8023         },
8024
8025         /**
8026          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8027          * @return {Roo.Element} this
8028          */
8029         clip : function(){
8030             if(!this.isClipped){
8031                this.isClipped = true;
8032                this.originalClip = {
8033                    "o": this.getStyle("overflow"),
8034                    "x": this.getStyle("overflow-x"),
8035                    "y": this.getStyle("overflow-y")
8036                };
8037                this.setStyle("overflow", "hidden");
8038                this.setStyle("overflow-x", "hidden");
8039                this.setStyle("overflow-y", "hidden");
8040             }
8041             return this;
8042         },
8043
8044         /**
8045          *  Return clipping (overflow) to original clipping before clip() was called
8046          * @return {Roo.Element} this
8047          */
8048         unclip : function(){
8049             if(this.isClipped){
8050                 this.isClipped = false;
8051                 var o = this.originalClip;
8052                 if(o.o){this.setStyle("overflow", o.o);}
8053                 if(o.x){this.setStyle("overflow-x", o.x);}
8054                 if(o.y){this.setStyle("overflow-y", o.y);}
8055             }
8056             return this;
8057         },
8058
8059
8060         /**
8061          * Gets the x,y coordinates specified by the anchor position on the element.
8062          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8063          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8064          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8065          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8066          * @return {Array} [x, y] An array containing the element's x and y coordinates
8067          */
8068         getAnchorXY : function(anchor, local, s){
8069             //Passing a different size is useful for pre-calculating anchors,
8070             //especially for anchored animations that change the el size.
8071
8072             var w, h, vp = false;
8073             if(!s){
8074                 var d = this.dom;
8075                 if(d == document.body || d == document){
8076                     vp = true;
8077                     w = D.getViewWidth(); h = D.getViewHeight();
8078                 }else{
8079                     w = this.getWidth(); h = this.getHeight();
8080                 }
8081             }else{
8082                 w = s.width;  h = s.height;
8083             }
8084             var x = 0, y = 0, r = Math.round;
8085             switch((anchor || "tl").toLowerCase()){
8086                 case "c":
8087                     x = r(w*.5);
8088                     y = r(h*.5);
8089                 break;
8090                 case "t":
8091                     x = r(w*.5);
8092                     y = 0;
8093                 break;
8094                 case "l":
8095                     x = 0;
8096                     y = r(h*.5);
8097                 break;
8098                 case "r":
8099                     x = w;
8100                     y = r(h*.5);
8101                 break;
8102                 case "b":
8103                     x = r(w*.5);
8104                     y = h;
8105                 break;
8106                 case "tl":
8107                     x = 0;
8108                     y = 0;
8109                 break;
8110                 case "bl":
8111                     x = 0;
8112                     y = h;
8113                 break;
8114                 case "br":
8115                     x = w;
8116                     y = h;
8117                 break;
8118                 case "tr":
8119                     x = w;
8120                     y = 0;
8121                 break;
8122             }
8123             if(local === true){
8124                 return [x, y];
8125             }
8126             if(vp){
8127                 var sc = this.getScroll();
8128                 return [x + sc.left, y + sc.top];
8129             }
8130             //Add the element's offset xy
8131             var o = this.getXY();
8132             return [x+o[0], y+o[1]];
8133         },
8134
8135         /**
8136          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8137          * supported position values.
8138          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8139          * @param {String} position The position to align to.
8140          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8141          * @return {Array} [x, y]
8142          */
8143         getAlignToXY : function(el, p, o){
8144             el = Roo.get(el);
8145             var d = this.dom;
8146             if(!el.dom){
8147                 throw "Element.alignTo with an element that doesn't exist";
8148             }
8149             var c = false; //constrain to viewport
8150             var p1 = "", p2 = "";
8151             o = o || [0,0];
8152
8153             if(!p){
8154                 p = "tl-bl";
8155             }else if(p == "?"){
8156                 p = "tl-bl?";
8157             }else if(p.indexOf("-") == -1){
8158                 p = "tl-" + p;
8159             }
8160             p = p.toLowerCase();
8161             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8162             if(!m){
8163                throw "Element.alignTo with an invalid alignment " + p;
8164             }
8165             p1 = m[1]; p2 = m[2]; c = !!m[3];
8166
8167             //Subtract the aligned el's internal xy from the target's offset xy
8168             //plus custom offset to get the aligned el's new offset xy
8169             var a1 = this.getAnchorXY(p1, true);
8170             var a2 = el.getAnchorXY(p2, false);
8171             var x = a2[0] - a1[0] + o[0];
8172             var y = a2[1] - a1[1] + o[1];
8173             if(c){
8174                 //constrain the aligned el to viewport if necessary
8175                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8176                 // 5px of margin for ie
8177                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8178
8179                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8180                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8181                 //otherwise swap the aligned el to the opposite border of the target.
8182                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8183                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8184                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8185                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8186
8187                var doc = document;
8188                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8189                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8190
8191                if((x+w) > dw + scrollX){
8192                     x = swapX ? r.left-w : dw+scrollX-w;
8193                 }
8194                if(x < scrollX){
8195                    x = swapX ? r.right : scrollX;
8196                }
8197                if((y+h) > dh + scrollY){
8198                     y = swapY ? r.top-h : dh+scrollY-h;
8199                 }
8200                if (y < scrollY){
8201                    y = swapY ? r.bottom : scrollY;
8202                }
8203             }
8204             return [x,y];
8205         },
8206
8207         // private
8208         getConstrainToXY : function(){
8209             var os = {top:0, left:0, bottom:0, right: 0};
8210
8211             return function(el, local, offsets, proposedXY){
8212                 el = Roo.get(el);
8213                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8214
8215                 var vw, vh, vx = 0, vy = 0;
8216                 if(el.dom == document.body || el.dom == document){
8217                     vw = Roo.lib.Dom.getViewWidth();
8218                     vh = Roo.lib.Dom.getViewHeight();
8219                 }else{
8220                     vw = el.dom.clientWidth;
8221                     vh = el.dom.clientHeight;
8222                     if(!local){
8223                         var vxy = el.getXY();
8224                         vx = vxy[0];
8225                         vy = vxy[1];
8226                     }
8227                 }
8228
8229                 var s = el.getScroll();
8230
8231                 vx += offsets.left + s.left;
8232                 vy += offsets.top + s.top;
8233
8234                 vw -= offsets.right;
8235                 vh -= offsets.bottom;
8236
8237                 var vr = vx+vw;
8238                 var vb = vy+vh;
8239
8240                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8241                 var x = xy[0], y = xy[1];
8242                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8243
8244                 // only move it if it needs it
8245                 var moved = false;
8246
8247                 // first validate right/bottom
8248                 if((x + w) > vr){
8249                     x = vr - w;
8250                     moved = true;
8251                 }
8252                 if((y + h) > vb){
8253                     y = vb - h;
8254                     moved = true;
8255                 }
8256                 // then make sure top/left isn't negative
8257                 if(x < vx){
8258                     x = vx;
8259                     moved = true;
8260                 }
8261                 if(y < vy){
8262                     y = vy;
8263                     moved = true;
8264                 }
8265                 return moved ? [x, y] : false;
8266             };
8267         }(),
8268
8269         // private
8270         adjustForConstraints : function(xy, parent, offsets){
8271             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8272         },
8273
8274         /**
8275          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8276          * document it aligns it to the viewport.
8277          * The position parameter is optional, and can be specified in any one of the following formats:
8278          * <ul>
8279          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8280          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8281          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8282          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8283          *   <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
8284          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8285          * </ul>
8286          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8287          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8288          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8289          * that specified in order to enforce the viewport constraints.
8290          * Following are all of the supported anchor positions:
8291     <pre>
8292     Value  Description
8293     -----  -----------------------------
8294     tl     The top left corner (default)
8295     t      The center of the top edge
8296     tr     The top right corner
8297     l      The center of the left edge
8298     c      In the center of the element
8299     r      The center of the right edge
8300     bl     The bottom left corner
8301     b      The center of the bottom edge
8302     br     The bottom right corner
8303     </pre>
8304     Example Usage:
8305     <pre><code>
8306     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8307     el.alignTo("other-el");
8308
8309     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8310     el.alignTo("other-el", "tr?");
8311
8312     // align the bottom right corner of el with the center left edge of other-el
8313     el.alignTo("other-el", "br-l?");
8314
8315     // align the center of el with the bottom left corner of other-el and
8316     // adjust the x position by -6 pixels (and the y position by 0)
8317     el.alignTo("other-el", "c-bl", [-6, 0]);
8318     </code></pre>
8319          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8320          * @param {String} position The position to align to.
8321          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8322          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8323          * @return {Roo.Element} this
8324          */
8325         alignTo : function(element, position, offsets, animate){
8326             var xy = this.getAlignToXY(element, position, offsets);
8327             this.setXY(xy, this.preanim(arguments, 3));
8328             return this;
8329         },
8330
8331         /**
8332          * Anchors an element to another element and realigns it when the window is resized.
8333          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8334          * @param {String} position The position to align to.
8335          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8336          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8337          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8338          * is a number, it is used as the buffer delay (defaults to 50ms).
8339          * @param {Function} callback The function to call after the animation finishes
8340          * @return {Roo.Element} this
8341          */
8342         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8343             var action = function(){
8344                 this.alignTo(el, alignment, offsets, animate);
8345                 Roo.callback(callback, this);
8346             };
8347             Roo.EventManager.onWindowResize(action, this);
8348             var tm = typeof monitorScroll;
8349             if(tm != 'undefined'){
8350                 Roo.EventManager.on(window, 'scroll', action, this,
8351                     {buffer: tm == 'number' ? monitorScroll : 50});
8352             }
8353             action.call(this); // align immediately
8354             return this;
8355         },
8356         /**
8357          * Clears any opacity settings from this element. Required in some cases for IE.
8358          * @return {Roo.Element} this
8359          */
8360         clearOpacity : function(){
8361             if (window.ActiveXObject) {
8362                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8363                     this.dom.style.filter = "";
8364                 }
8365             } else {
8366                 this.dom.style.opacity = "";
8367                 this.dom.style["-moz-opacity"] = "";
8368                 this.dom.style["-khtml-opacity"] = "";
8369             }
8370             return this;
8371         },
8372
8373         /**
8374          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8375          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8376          * @return {Roo.Element} this
8377          */
8378         hide : function(animate){
8379             this.setVisible(false, this.preanim(arguments, 0));
8380             return this;
8381         },
8382
8383         /**
8384         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8385         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8386          * @return {Roo.Element} this
8387          */
8388         show : function(animate){
8389             this.setVisible(true, this.preanim(arguments, 0));
8390             return this;
8391         },
8392
8393         /**
8394          * @private Test if size has a unit, otherwise appends the default
8395          */
8396         addUnits : function(size){
8397             return Roo.Element.addUnits(size, this.defaultUnit);
8398         },
8399
8400         /**
8401          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8402          * @return {Roo.Element} this
8403          */
8404         beginMeasure : function(){
8405             var el = this.dom;
8406             if(el.offsetWidth || el.offsetHeight){
8407                 return this; // offsets work already
8408             }
8409             var changed = [];
8410             var p = this.dom, b = document.body; // start with this element
8411             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8412                 var pe = Roo.get(p);
8413                 if(pe.getStyle('display') == 'none'){
8414                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8415                     p.style.visibility = "hidden";
8416                     p.style.display = "block";
8417                 }
8418                 p = p.parentNode;
8419             }
8420             this._measureChanged = changed;
8421             return this;
8422
8423         },
8424
8425         /**
8426          * Restores displays to before beginMeasure was called
8427          * @return {Roo.Element} this
8428          */
8429         endMeasure : function(){
8430             var changed = this._measureChanged;
8431             if(changed){
8432                 for(var i = 0, len = changed.length; i < len; i++) {
8433                     var r = changed[i];
8434                     r.el.style.visibility = r.visibility;
8435                     r.el.style.display = "none";
8436                 }
8437                 this._measureChanged = null;
8438             }
8439             return this;
8440         },
8441
8442         /**
8443         * Update the innerHTML of this element, optionally searching for and processing scripts
8444         * @param {String} html The new HTML
8445         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8446         * @param {Function} callback For async script loading you can be noticed when the update completes
8447         * @return {Roo.Element} this
8448          */
8449         update : function(html, loadScripts, callback){
8450             if(typeof html == "undefined"){
8451                 html = "";
8452             }
8453             if(loadScripts !== true){
8454                 this.dom.innerHTML = html;
8455                 if(typeof callback == "function"){
8456                     callback();
8457                 }
8458                 return this;
8459             }
8460             var id = Roo.id();
8461             var dom = this.dom;
8462
8463             html += '<span id="' + id + '"></span>';
8464
8465             E.onAvailable(id, function(){
8466                 var hd = document.getElementsByTagName("head")[0];
8467                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8468                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8469                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8470
8471                 var match;
8472                 while(match = re.exec(html)){
8473                     var attrs = match[1];
8474                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8475                     if(srcMatch && srcMatch[2]){
8476                        var s = document.createElement("script");
8477                        s.src = srcMatch[2];
8478                        var typeMatch = attrs.match(typeRe);
8479                        if(typeMatch && typeMatch[2]){
8480                            s.type = typeMatch[2];
8481                        }
8482                        hd.appendChild(s);
8483                     }else if(match[2] && match[2].length > 0){
8484                         if(window.execScript) {
8485                            window.execScript(match[2]);
8486                         } else {
8487                             /**
8488                              * eval:var:id
8489                              * eval:var:dom
8490                              * eval:var:html
8491                              * 
8492                              */
8493                            window.eval(match[2]);
8494                         }
8495                     }
8496                 }
8497                 var el = document.getElementById(id);
8498                 if(el){el.parentNode.removeChild(el);}
8499                 if(typeof callback == "function"){
8500                     callback();
8501                 }
8502             });
8503             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8504             return this;
8505         },
8506
8507         /**
8508          * Direct access to the UpdateManager update() method (takes the same parameters).
8509          * @param {String/Function} url The url for this request or a function to call to get the url
8510          * @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}
8511          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8512          * @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.
8513          * @return {Roo.Element} this
8514          */
8515         load : function(){
8516             var um = this.getUpdateManager();
8517             um.update.apply(um, arguments);
8518             return this;
8519         },
8520
8521         /**
8522         * Gets this element's UpdateManager
8523         * @return {Roo.UpdateManager} The UpdateManager
8524         */
8525         getUpdateManager : function(){
8526             if(!this.updateManager){
8527                 this.updateManager = new Roo.UpdateManager(this);
8528             }
8529             return this.updateManager;
8530         },
8531
8532         /**
8533          * Disables text selection for this element (normalized across browsers)
8534          * @return {Roo.Element} this
8535          */
8536         unselectable : function(){
8537             this.dom.unselectable = "on";
8538             this.swallowEvent("selectstart", true);
8539             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8540             this.addClass("x-unselectable");
8541             return this;
8542         },
8543
8544         /**
8545         * Calculates the x, y to center this element on the screen
8546         * @return {Array} The x, y values [x, y]
8547         */
8548         getCenterXY : function(){
8549             return this.getAlignToXY(document, 'c-c');
8550         },
8551
8552         /**
8553         * Centers the Element in either the viewport, or another Element.
8554         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8555         */
8556         center : function(centerIn){
8557             this.alignTo(centerIn || document, 'c-c');
8558             return this;
8559         },
8560
8561         /**
8562          * Tests various css rules/browsers to determine if this element uses a border box
8563          * @return {Boolean}
8564          */
8565         isBorderBox : function(){
8566             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8567         },
8568
8569         /**
8570          * Return a box {x, y, width, height} that can be used to set another elements
8571          * size/location to match this element.
8572          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8573          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8574          * @return {Object} box An object in the format {x, y, width, height}
8575          */
8576         getBox : function(contentBox, local){
8577             var xy;
8578             if(!local){
8579                 xy = this.getXY();
8580             }else{
8581                 var left = parseInt(this.getStyle("left"), 10) || 0;
8582                 var top = parseInt(this.getStyle("top"), 10) || 0;
8583                 xy = [left, top];
8584             }
8585             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8586             if(!contentBox){
8587                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8588             }else{
8589                 var l = this.getBorderWidth("l")+this.getPadding("l");
8590                 var r = this.getBorderWidth("r")+this.getPadding("r");
8591                 var t = this.getBorderWidth("t")+this.getPadding("t");
8592                 var b = this.getBorderWidth("b")+this.getPadding("b");
8593                 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)};
8594             }
8595             bx.right = bx.x + bx.width;
8596             bx.bottom = bx.y + bx.height;
8597             return bx;
8598         },
8599
8600         /**
8601          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8602          for more information about the sides.
8603          * @param {String} sides
8604          * @return {Number}
8605          */
8606         getFrameWidth : function(sides, onlyContentBox){
8607             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8608         },
8609
8610         /**
8611          * 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.
8612          * @param {Object} box The box to fill {x, y, width, height}
8613          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8614          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8615          * @return {Roo.Element} this
8616          */
8617         setBox : function(box, adjust, animate){
8618             var w = box.width, h = box.height;
8619             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8620                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8621                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8622             }
8623             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8624             return this;
8625         },
8626
8627         /**
8628          * Forces the browser to repaint this element
8629          * @return {Roo.Element} this
8630          */
8631          repaint : function(){
8632             var dom = this.dom;
8633             this.addClass("x-repaint");
8634             setTimeout(function(){
8635                 Roo.get(dom).removeClass("x-repaint");
8636             }, 1);
8637             return this;
8638         },
8639
8640         /**
8641          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8642          * then it returns the calculated width of the sides (see getPadding)
8643          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8644          * @return {Object/Number}
8645          */
8646         getMargins : function(side){
8647             if(!side){
8648                 return {
8649                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8650                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8651                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8652                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8653                 };
8654             }else{
8655                 return this.addStyles(side, El.margins);
8656              }
8657         },
8658
8659         // private
8660         addStyles : function(sides, styles){
8661             var val = 0, v, w;
8662             for(var i = 0, len = sides.length; i < len; i++){
8663                 v = this.getStyle(styles[sides.charAt(i)]);
8664                 if(v){
8665                      w = parseInt(v, 10);
8666                      if(w){ val += w; }
8667                 }
8668             }
8669             return val;
8670         },
8671
8672         /**
8673          * Creates a proxy element of this element
8674          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8675          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8676          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8677          * @return {Roo.Element} The new proxy element
8678          */
8679         createProxy : function(config, renderTo, matchBox){
8680             if(renderTo){
8681                 renderTo = Roo.getDom(renderTo);
8682             }else{
8683                 renderTo = document.body;
8684             }
8685             config = typeof config == "object" ?
8686                 config : {tag : "div", cls: config};
8687             var proxy = Roo.DomHelper.append(renderTo, config, true);
8688             if(matchBox){
8689                proxy.setBox(this.getBox());
8690             }
8691             return proxy;
8692         },
8693
8694         /**
8695          * Puts a mask over this element to disable user interaction. Requires core.css.
8696          * This method can only be applied to elements which accept child nodes.
8697          * @param {String} msg (optional) A message to display in the mask
8698          * @param {String} msgCls (optional) A css class to apply to the msg element
8699          * @return {Element} The mask  element
8700          */
8701         mask : function(msg, msgCls){
8702             if(this.getStyle("position") == "static"){
8703                 this.setStyle("position", "relative");
8704             }
8705             if(!this._mask){
8706                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8707             }
8708             this.addClass("x-masked");
8709             this._mask.setDisplayed(true);
8710             if(typeof msg == 'string'){
8711                 if(!this._maskMsg){
8712                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8713                 }
8714                 var mm = this._maskMsg;
8715                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8716                 mm.dom.firstChild.innerHTML = msg;
8717                 mm.setDisplayed(true);
8718                 mm.center(this);
8719             }
8720             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8721                 this._mask.setHeight(this.getHeight());
8722             }
8723             return this._mask;
8724         },
8725
8726         /**
8727          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8728          * it is cached for reuse.
8729          */
8730         unmask : function(removeEl){
8731             if(this._mask){
8732                 if(removeEl === true){
8733                     this._mask.remove();
8734                     delete this._mask;
8735                     if(this._maskMsg){
8736                         this._maskMsg.remove();
8737                         delete this._maskMsg;
8738                     }
8739                 }else{
8740                     this._mask.setDisplayed(false);
8741                     if(this._maskMsg){
8742                         this._maskMsg.setDisplayed(false);
8743                     }
8744                 }
8745             }
8746             this.removeClass("x-masked");
8747         },
8748
8749         /**
8750          * Returns true if this element is masked
8751          * @return {Boolean}
8752          */
8753         isMasked : function(){
8754             return this._mask && this._mask.isVisible();
8755         },
8756
8757         /**
8758          * Creates an iframe shim for this element to keep selects and other windowed objects from
8759          * showing through.
8760          * @return {Roo.Element} The new shim element
8761          */
8762         createShim : function(){
8763             var el = document.createElement('iframe');
8764             el.frameBorder = 'no';
8765             el.className = 'roo-shim';
8766             if(Roo.isIE && Roo.isSecure){
8767                 el.src = Roo.SSL_SECURE_URL;
8768             }
8769             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8770             shim.autoBoxAdjust = false;
8771             return shim;
8772         },
8773
8774         /**
8775          * Removes this element from the DOM and deletes it from the cache
8776          */
8777         remove : function(){
8778             if(this.dom.parentNode){
8779                 this.dom.parentNode.removeChild(this.dom);
8780             }
8781             delete El.cache[this.dom.id];
8782         },
8783
8784         /**
8785          * Sets up event handlers to add and remove a css class when the mouse is over this element
8786          * @param {String} className
8787          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8788          * mouseout events for children elements
8789          * @return {Roo.Element} this
8790          */
8791         addClassOnOver : function(className, preventFlicker){
8792             this.on("mouseover", function(){
8793                 Roo.fly(this, '_internal').addClass(className);
8794             }, this.dom);
8795             var removeFn = function(e){
8796                 if(preventFlicker !== true || !e.within(this, true)){
8797                     Roo.fly(this, '_internal').removeClass(className);
8798                 }
8799             };
8800             this.on("mouseout", removeFn, this.dom);
8801             return this;
8802         },
8803
8804         /**
8805          * Sets up event handlers to add and remove a css class when this element has the focus
8806          * @param {String} className
8807          * @return {Roo.Element} this
8808          */
8809         addClassOnFocus : function(className){
8810             this.on("focus", function(){
8811                 Roo.fly(this, '_internal').addClass(className);
8812             }, this.dom);
8813             this.on("blur", function(){
8814                 Roo.fly(this, '_internal').removeClass(className);
8815             }, this.dom);
8816             return this;
8817         },
8818         /**
8819          * 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)
8820          * @param {String} className
8821          * @return {Roo.Element} this
8822          */
8823         addClassOnClick : function(className){
8824             var dom = this.dom;
8825             this.on("mousedown", function(){
8826                 Roo.fly(dom, '_internal').addClass(className);
8827                 var d = Roo.get(document);
8828                 var fn = function(){
8829                     Roo.fly(dom, '_internal').removeClass(className);
8830                     d.removeListener("mouseup", fn);
8831                 };
8832                 d.on("mouseup", fn);
8833             });
8834             return this;
8835         },
8836
8837         /**
8838          * Stops the specified event from bubbling and optionally prevents the default action
8839          * @param {String} eventName
8840          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8841          * @return {Roo.Element} this
8842          */
8843         swallowEvent : function(eventName, preventDefault){
8844             var fn = function(e){
8845                 e.stopPropagation();
8846                 if(preventDefault){
8847                     e.preventDefault();
8848                 }
8849             };
8850             if(eventName instanceof Array){
8851                 for(var i = 0, len = eventName.length; i < len; i++){
8852                      this.on(eventName[i], fn);
8853                 }
8854                 return this;
8855             }
8856             this.on(eventName, fn);
8857             return this;
8858         },
8859
8860         /**
8861          * @private
8862          */
8863       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8864
8865         /**
8866          * Sizes this element to its parent element's dimensions performing
8867          * neccessary box adjustments.
8868          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8869          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8870          * @return {Roo.Element} this
8871          */
8872         fitToParent : function(monitorResize, targetParent) {
8873           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8874           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8875           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8876             return;
8877           }
8878           var p = Roo.get(targetParent || this.dom.parentNode);
8879           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8880           if (monitorResize === true) {
8881             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8882             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8883           }
8884           return this;
8885         },
8886
8887         /**
8888          * Gets the next sibling, skipping text nodes
8889          * @return {HTMLElement} The next sibling or null
8890          */
8891         getNextSibling : function(){
8892             var n = this.dom.nextSibling;
8893             while(n && n.nodeType != 1){
8894                 n = n.nextSibling;
8895             }
8896             return n;
8897         },
8898
8899         /**
8900          * Gets the previous sibling, skipping text nodes
8901          * @return {HTMLElement} The previous sibling or null
8902          */
8903         getPrevSibling : function(){
8904             var n = this.dom.previousSibling;
8905             while(n && n.nodeType != 1){
8906                 n = n.previousSibling;
8907             }
8908             return n;
8909         },
8910
8911
8912         /**
8913          * Appends the passed element(s) to this element
8914          * @param {String/HTMLElement/Array/Element/CompositeElement} el
8915          * @return {Roo.Element} this
8916          */
8917         appendChild: function(el){
8918             el = Roo.get(el);
8919             el.appendTo(this);
8920             return this;
8921         },
8922
8923         /**
8924          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8925          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
8926          * automatically generated with the specified attributes.
8927          * @param {HTMLElement} insertBefore (optional) a child element of this element
8928          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8929          * @return {Roo.Element} The new child element
8930          */
8931         createChild: function(config, insertBefore, returnDom){
8932             config = config || {tag:'div'};
8933             if(insertBefore){
8934                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8935             }
8936             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
8937         },
8938
8939         /**
8940          * Appends this element to the passed element
8941          * @param {String/HTMLElement/Element} el The new parent element
8942          * @return {Roo.Element} this
8943          */
8944         appendTo: function(el){
8945             el = Roo.getDom(el);
8946             el.appendChild(this.dom);
8947             return this;
8948         },
8949
8950         /**
8951          * Inserts this element before the passed element in the DOM
8952          * @param {String/HTMLElement/Element} el The element to insert before
8953          * @return {Roo.Element} this
8954          */
8955         insertBefore: function(el){
8956             el = Roo.getDom(el);
8957             el.parentNode.insertBefore(this.dom, el);
8958             return this;
8959         },
8960
8961         /**
8962          * Inserts this element after the passed element in the DOM
8963          * @param {String/HTMLElement/Element} el The element to insert after
8964          * @return {Roo.Element} this
8965          */
8966         insertAfter: function(el){
8967             el = Roo.getDom(el);
8968             el.parentNode.insertBefore(this.dom, el.nextSibling);
8969             return this;
8970         },
8971
8972         /**
8973          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8974          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8975          * @return {Roo.Element} The new child
8976          */
8977         insertFirst: function(el, returnDom){
8978             el = el || {};
8979             if(typeof el == 'object' && !el.nodeType){ // dh config
8980                 return this.createChild(el, this.dom.firstChild, returnDom);
8981             }else{
8982                 el = Roo.getDom(el);
8983                 this.dom.insertBefore(el, this.dom.firstChild);
8984                 return !returnDom ? Roo.get(el) : el;
8985             }
8986         },
8987
8988         /**
8989          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8990          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8991          * @param {String} where (optional) 'before' or 'after' defaults to before
8992          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8993          * @return {Roo.Element} the inserted Element
8994          */
8995         insertSibling: function(el, where, returnDom){
8996             where = where ? where.toLowerCase() : 'before';
8997             el = el || {};
8998             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8999
9000             if(typeof el == 'object' && !el.nodeType){ // dh config
9001                 if(where == 'after' && !this.dom.nextSibling){
9002                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9003                 }else{
9004                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9005                 }
9006
9007             }else{
9008                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9009                             where == 'before' ? this.dom : this.dom.nextSibling);
9010                 if(!returnDom){
9011                     rt = Roo.get(rt);
9012                 }
9013             }
9014             return rt;
9015         },
9016
9017         /**
9018          * Creates and wraps this element with another element
9019          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9020          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9021          * @return {HTMLElement/Element} The newly created wrapper element
9022          */
9023         wrap: function(config, returnDom){
9024             if(!config){
9025                 config = {tag: "div"};
9026             }
9027             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9028             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9029             return newEl;
9030         },
9031
9032         /**
9033          * Replaces the passed element with this element
9034          * @param {String/HTMLElement/Element} el The element to replace
9035          * @return {Roo.Element} this
9036          */
9037         replace: function(el){
9038             el = Roo.get(el);
9039             this.insertBefore(el);
9040             el.remove();
9041             return this;
9042         },
9043
9044         /**
9045          * Inserts an html fragment into this element
9046          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9047          * @param {String} html The HTML fragment
9048          * @param {Boolean} returnEl True to return an Roo.Element
9049          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9050          */
9051         insertHtml : function(where, html, returnEl){
9052             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9053             return returnEl ? Roo.get(el) : el;
9054         },
9055
9056         /**
9057          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9058          * @param {Object} o The object with the attributes
9059          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9060          * @return {Roo.Element} this
9061          */
9062         set : function(o, useSet){
9063             var el = this.dom;
9064             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9065             for(var attr in o){
9066                 if(attr == "style" || typeof o[attr] == "function") continue;
9067                 if(attr=="cls"){
9068                     el.className = o["cls"];
9069                 }else{
9070                     if(useSet) el.setAttribute(attr, o[attr]);
9071                     else el[attr] = o[attr];
9072                 }
9073             }
9074             if(o.style){
9075                 Roo.DomHelper.applyStyles(el, o.style);
9076             }
9077             return this;
9078         },
9079
9080         /**
9081          * Convenience method for constructing a KeyMap
9082          * @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:
9083          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9084          * @param {Function} fn The function to call
9085          * @param {Object} scope (optional) The scope of the function
9086          * @return {Roo.KeyMap} The KeyMap created
9087          */
9088         addKeyListener : function(key, fn, scope){
9089             var config;
9090             if(typeof key != "object" || key instanceof Array){
9091                 config = {
9092                     key: key,
9093                     fn: fn,
9094                     scope: scope
9095                 };
9096             }else{
9097                 config = {
9098                     key : key.key,
9099                     shift : key.shift,
9100                     ctrl : key.ctrl,
9101                     alt : key.alt,
9102                     fn: fn,
9103                     scope: scope
9104                 };
9105             }
9106             return new Roo.KeyMap(this, config);
9107         },
9108
9109         /**
9110          * Creates a KeyMap for this element
9111          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9112          * @return {Roo.KeyMap} The KeyMap created
9113          */
9114         addKeyMap : function(config){
9115             return new Roo.KeyMap(this, config);
9116         },
9117
9118         /**
9119          * Returns true if this element is scrollable.
9120          * @return {Boolean}
9121          */
9122          isScrollable : function(){
9123             var dom = this.dom;
9124             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9125         },
9126
9127         /**
9128          * 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().
9129          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9130          * @param {Number} value The new scroll value
9131          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9132          * @return {Element} this
9133          */
9134
9135         scrollTo : function(side, value, animate){
9136             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9137             if(!animate || !A){
9138                 this.dom[prop] = value;
9139             }else{
9140                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9141                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9142             }
9143             return this;
9144         },
9145
9146         /**
9147          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9148          * within this element's scrollable range.
9149          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9150          * @param {Number} distance How far to scroll the element in pixels
9151          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9152          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9153          * was scrolled as far as it could go.
9154          */
9155          scroll : function(direction, distance, animate){
9156              if(!this.isScrollable()){
9157                  return;
9158              }
9159              var el = this.dom;
9160              var l = el.scrollLeft, t = el.scrollTop;
9161              var w = el.scrollWidth, h = el.scrollHeight;
9162              var cw = el.clientWidth, ch = el.clientHeight;
9163              direction = direction.toLowerCase();
9164              var scrolled = false;
9165              var a = this.preanim(arguments, 2);
9166              switch(direction){
9167                  case "l":
9168                  case "left":
9169                      if(w - l > cw){
9170                          var v = Math.min(l + distance, w-cw);
9171                          this.scrollTo("left", v, a);
9172                          scrolled = true;
9173                      }
9174                      break;
9175                 case "r":
9176                 case "right":
9177                      if(l > 0){
9178                          var v = Math.max(l - distance, 0);
9179                          this.scrollTo("left", v, a);
9180                          scrolled = true;
9181                      }
9182                      break;
9183                 case "t":
9184                 case "top":
9185                 case "up":
9186                      if(t > 0){
9187                          var v = Math.max(t - distance, 0);
9188                          this.scrollTo("top", v, a);
9189                          scrolled = true;
9190                      }
9191                      break;
9192                 case "b":
9193                 case "bottom":
9194                 case "down":
9195                      if(h - t > ch){
9196                          var v = Math.min(t + distance, h-ch);
9197                          this.scrollTo("top", v, a);
9198                          scrolled = true;
9199                      }
9200                      break;
9201              }
9202              return scrolled;
9203         },
9204
9205         /**
9206          * Translates the passed page coordinates into left/top css values for this element
9207          * @param {Number/Array} x The page x or an array containing [x, y]
9208          * @param {Number} y The page y
9209          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9210          */
9211         translatePoints : function(x, y){
9212             if(typeof x == 'object' || x instanceof Array){
9213                 y = x[1]; x = x[0];
9214             }
9215             var p = this.getStyle('position');
9216             var o = this.getXY();
9217
9218             var l = parseInt(this.getStyle('left'), 10);
9219             var t = parseInt(this.getStyle('top'), 10);
9220
9221             if(isNaN(l)){
9222                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9223             }
9224             if(isNaN(t)){
9225                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9226             }
9227
9228             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9229         },
9230
9231         /**
9232          * Returns the current scroll position of the element.
9233          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9234          */
9235         getScroll : function(){
9236             var d = this.dom, doc = document;
9237             if(d == doc || d == doc.body){
9238                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9239                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9240                 return {left: l, top: t};
9241             }else{
9242                 return {left: d.scrollLeft, top: d.scrollTop};
9243             }
9244         },
9245
9246         /**
9247          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9248          * are convert to standard 6 digit hex color.
9249          * @param {String} attr The css attribute
9250          * @param {String} defaultValue The default value to use when a valid color isn't found
9251          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9252          * YUI color anims.
9253          */
9254         getColor : function(attr, defaultValue, prefix){
9255             var v = this.getStyle(attr);
9256             if(!v || v == "transparent" || v == "inherit") {
9257                 return defaultValue;
9258             }
9259             var color = typeof prefix == "undefined" ? "#" : prefix;
9260             if(v.substr(0, 4) == "rgb("){
9261                 var rvs = v.slice(4, v.length -1).split(",");
9262                 for(var i = 0; i < 3; i++){
9263                     var h = parseInt(rvs[i]).toString(16);
9264                     if(h < 16){
9265                         h = "0" + h;
9266                     }
9267                     color += h;
9268                 }
9269             } else {
9270                 if(v.substr(0, 1) == "#"){
9271                     if(v.length == 4) {
9272                         for(var i = 1; i < 4; i++){
9273                             var c = v.charAt(i);
9274                             color +=  c + c;
9275                         }
9276                     }else if(v.length == 7){
9277                         color += v.substr(1);
9278                     }
9279                 }
9280             }
9281             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9282         },
9283
9284         /**
9285          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9286          * gradient background, rounded corners and a 4-way shadow.
9287          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9288          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9289          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9290          * @return {Roo.Element} this
9291          */
9292         boxWrap : function(cls){
9293             cls = cls || 'x-box';
9294             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9295             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9296             return el;
9297         },
9298
9299         /**
9300          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9301          * @param {String} namespace The namespace in which to look for the attribute
9302          * @param {String} name The attribute name
9303          * @return {String} The attribute value
9304          */
9305         getAttributeNS : Roo.isIE ? function(ns, name){
9306             var d = this.dom;
9307             var type = typeof d[ns+":"+name];
9308             if(type != 'undefined' && type != 'unknown'){
9309                 return d[ns+":"+name];
9310             }
9311             return d[name];
9312         } : function(ns, name){
9313             var d = this.dom;
9314             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9315         }
9316     };
9317
9318     var ep = El.prototype;
9319
9320     /**
9321      * Appends an event handler (Shorthand for addListener)
9322      * @param {String}   eventName     The type of event to append
9323      * @param {Function} fn        The method the event invokes
9324      * @param {Object} scope       (optional) The scope (this object) of the fn
9325      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9326      * @method
9327      */
9328     ep.on = ep.addListener;
9329         // backwards compat
9330     ep.mon = ep.addListener;
9331
9332     /**
9333      * Removes an event handler from this element (shorthand for removeListener)
9334      * @param {String} eventName the type of event to remove
9335      * @param {Function} fn the method the event invokes
9336      * @return {Roo.Element} this
9337      * @method
9338      */
9339     ep.un = ep.removeListener;
9340
9341     /**
9342      * true to automatically adjust width and height settings for box-model issues (default to true)
9343      */
9344     ep.autoBoxAdjust = true;
9345
9346     // private
9347     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9348
9349     // private
9350     El.addUnits = function(v, defaultUnit){
9351         if(v === "" || v == "auto"){
9352             return v;
9353         }
9354         if(v === undefined){
9355             return '';
9356         }
9357         if(typeof v == "number" || !El.unitPattern.test(v)){
9358             return v + (defaultUnit || 'px');
9359         }
9360         return v;
9361     };
9362
9363     // special markup used throughout Roo when box wrapping elements
9364     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>';
9365     /**
9366      * Visibility mode constant - Use visibility to hide element
9367      * @static
9368      * @type Number
9369      */
9370     El.VISIBILITY = 1;
9371     /**
9372      * Visibility mode constant - Use display to hide element
9373      * @static
9374      * @type Number
9375      */
9376     El.DISPLAY = 2;
9377
9378     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9379     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9380     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9381
9382
9383
9384     /**
9385      * @private
9386      */
9387     El.cache = {};
9388
9389     var docEl;
9390
9391     /**
9392      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9393      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9394      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9395      * @return {Element} The Element object
9396      * @static
9397      */
9398     El.get = function(el){
9399         var ex, elm, id;
9400         if(!el){ return null; }
9401         if(typeof el == "string"){ // element id
9402             if(!(elm = document.getElementById(el))){
9403                 return null;
9404             }
9405             if(ex = El.cache[el]){
9406                 ex.dom = elm;
9407             }else{
9408                 ex = El.cache[el] = new El(elm);
9409             }
9410             return ex;
9411         }else if(el.tagName){ // dom element
9412             if(!(id = el.id)){
9413                 id = Roo.id(el);
9414             }
9415             if(ex = El.cache[id]){
9416                 ex.dom = el;
9417             }else{
9418                 ex = El.cache[id] = new El(el);
9419             }
9420             return ex;
9421         }else if(el instanceof El){
9422             if(el != docEl){
9423                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9424                                                               // catch case where it hasn't been appended
9425                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9426             }
9427             return el;
9428         }else if(el.isComposite){
9429             return el;
9430         }else if(el instanceof Array){
9431             return El.select(el);
9432         }else if(el == document){
9433             // create a bogus element object representing the document object
9434             if(!docEl){
9435                 var f = function(){};
9436                 f.prototype = El.prototype;
9437                 docEl = new f();
9438                 docEl.dom = document;
9439             }
9440             return docEl;
9441         }
9442         return null;
9443     };
9444
9445     // private
9446     El.uncache = function(el){
9447         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9448             if(a[i]){
9449                 delete El.cache[a[i].id || a[i]];
9450             }
9451         }
9452     };
9453
9454     // private
9455     // Garbage collection - uncache elements/purge listeners on orphaned elements
9456     // so we don't hold a reference and cause the browser to retain them
9457     El.garbageCollect = function(){
9458         if(!Roo.enableGarbageCollector){
9459             clearInterval(El.collectorThread);
9460             return;
9461         }
9462         for(var eid in El.cache){
9463             var el = El.cache[eid], d = el.dom;
9464             // -------------------------------------------------------
9465             // Determining what is garbage:
9466             // -------------------------------------------------------
9467             // !d
9468             // dom node is null, definitely garbage
9469             // -------------------------------------------------------
9470             // !d.parentNode
9471             // no parentNode == direct orphan, definitely garbage
9472             // -------------------------------------------------------
9473             // !d.offsetParent && !document.getElementById(eid)
9474             // display none elements have no offsetParent so we will
9475             // also try to look it up by it's id. However, check
9476             // offsetParent first so we don't do unneeded lookups.
9477             // This enables collection of elements that are not orphans
9478             // directly, but somewhere up the line they have an orphan
9479             // parent.
9480             // -------------------------------------------------------
9481             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9482                 delete El.cache[eid];
9483                 if(d && Roo.enableListenerCollection){
9484                     E.purgeElement(d);
9485                 }
9486             }
9487         }
9488     }
9489     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9490
9491
9492     // dom is optional
9493     El.Flyweight = function(dom){
9494         this.dom = dom;
9495     };
9496     El.Flyweight.prototype = El.prototype;
9497
9498     El._flyweights = {};
9499     /**
9500      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9501      * the dom node can be overwritten by other code.
9502      * @param {String/HTMLElement} el The dom node or id
9503      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9504      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9505      * @static
9506      * @return {Element} The shared Element object
9507      */
9508     El.fly = function(el, named){
9509         named = named || '_global';
9510         el = Roo.getDom(el);
9511         if(!el){
9512             return null;
9513         }
9514         if(!El._flyweights[named]){
9515             El._flyweights[named] = new El.Flyweight();
9516         }
9517         El._flyweights[named].dom = el;
9518         return El._flyweights[named];
9519     };
9520
9521     /**
9522      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9523      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9524      * Shorthand of {@link Roo.Element#get}
9525      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9526      * @return {Element} The Element object
9527      * @member Roo
9528      * @method get
9529      */
9530     Roo.get = El.get;
9531     /**
9532      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9533      * the dom node can be overwritten by other code.
9534      * Shorthand of {@link Roo.Element#fly}
9535      * @param {String/HTMLElement} el The dom node or id
9536      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9537      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9538      * @static
9539      * @return {Element} The shared Element object
9540      * @member Roo
9541      * @method fly
9542      */
9543     Roo.fly = El.fly;
9544
9545     // speedy lookup for elements never to box adjust
9546     var noBoxAdjust = Roo.isStrict ? {
9547         select:1
9548     } : {
9549         input:1, select:1, textarea:1
9550     };
9551     if(Roo.isIE || Roo.isGecko){
9552         noBoxAdjust['button'] = 1;
9553     }
9554
9555
9556     Roo.EventManager.on(window, 'unload', function(){
9557         delete El.cache;
9558         delete El._flyweights;
9559     });
9560 })();
9561
9562
9563
9564
9565 if(Roo.DomQuery){
9566     Roo.Element.selectorFunction = Roo.DomQuery.select;
9567 }
9568
9569 Roo.Element.select = function(selector, unique, root){
9570     var els;
9571     if(typeof selector == "string"){
9572         els = Roo.Element.selectorFunction(selector, root);
9573     }else if(selector.length !== undefined){
9574         els = selector;
9575     }else{
9576         throw "Invalid selector";
9577     }
9578     if(unique === true){
9579         return new Roo.CompositeElement(els);
9580     }else{
9581         return new Roo.CompositeElementLite(els);
9582     }
9583 };
9584 /**
9585  * Selects elements based on the passed CSS selector to enable working on them as 1.
9586  * @param {String/Array} selector The CSS selector or an array of elements
9587  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9588  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9589  * @return {CompositeElementLite/CompositeElement}
9590  * @member Roo
9591  * @method select
9592  */
9593 Roo.select = Roo.Element.select;
9594
9595
9596
9597
9598
9599
9600
9601
9602
9603
9604
9605
9606
9607
9608 /*
9609  * Based on:
9610  * Ext JS Library 1.1.1
9611  * Copyright(c) 2006-2007, Ext JS, LLC.
9612  *
9613  * Originally Released Under LGPL - original licence link has changed is not relivant.
9614  *
9615  * Fork - LGPL
9616  * <script type="text/javascript">
9617  */
9618
9619
9620
9621 //Notifies Element that fx methods are available
9622 Roo.enableFx = true;
9623
9624 /**
9625  * @class Roo.Fx
9626  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9627  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9628  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9629  * Element effects to work.</p><br/>
9630  *
9631  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9632  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9633  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9634  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9635  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9636  * expected results and should be done with care.</p><br/>
9637  *
9638  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9639  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9640 <pre>
9641 Value  Description
9642 -----  -----------------------------
9643 tl     The top left corner
9644 t      The center of the top edge
9645 tr     The top right corner
9646 l      The center of the left edge
9647 r      The center of the right edge
9648 bl     The bottom left corner
9649 b      The center of the bottom edge
9650 br     The bottom right corner
9651 </pre>
9652  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9653  * below are common options that can be passed to any Fx method.</b>
9654  * @cfg {Function} callback A function called when the effect is finished
9655  * @cfg {Object} scope The scope of the effect function
9656  * @cfg {String} easing A valid Easing value for the effect
9657  * @cfg {String} afterCls A css class to apply after the effect
9658  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9659  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9660  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9661  * effects that end with the element being visually hidden, ignored otherwise)
9662  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9663  * a function which returns such a specification that will be applied to the Element after the effect finishes
9664  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9665  * @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
9666  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9667  */
9668 Roo.Fx = {
9669         /**
9670          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9671          * origin for the slide effect.  This function automatically handles wrapping the element with
9672          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9673          * Usage:
9674          *<pre><code>
9675 // default: slide the element in from the top
9676 el.slideIn();
9677
9678 // custom: slide the element in from the right with a 2-second duration
9679 el.slideIn('r', { duration: 2 });
9680
9681 // common config options shown with default values
9682 el.slideIn('t', {
9683     easing: 'easeOut',
9684     duration: .5
9685 });
9686 </code></pre>
9687          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9688          * @param {Object} options (optional) Object literal with any of the Fx config options
9689          * @return {Roo.Element} The Element
9690          */
9691     slideIn : function(anchor, o){
9692         var el = this.getFxEl();
9693         o = o || {};
9694
9695         el.queueFx(o, function(){
9696
9697             anchor = anchor || "t";
9698
9699             // fix display to visibility
9700             this.fixDisplay();
9701
9702             // restore values after effect
9703             var r = this.getFxRestore();
9704             var b = this.getBox();
9705             // fixed size for slide
9706             this.setSize(b);
9707
9708             // wrap if needed
9709             var wrap = this.fxWrap(r.pos, o, "hidden");
9710
9711             var st = this.dom.style;
9712             st.visibility = "visible";
9713             st.position = "absolute";
9714
9715             // clear out temp styles after slide and unwrap
9716             var after = function(){
9717                 el.fxUnwrap(wrap, r.pos, o);
9718                 st.width = r.width;
9719                 st.height = r.height;
9720                 el.afterFx(o);
9721             };
9722             // time to calc the positions
9723             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9724
9725             switch(anchor.toLowerCase()){
9726                 case "t":
9727                     wrap.setSize(b.width, 0);
9728                     st.left = st.bottom = "0";
9729                     a = {height: bh};
9730                 break;
9731                 case "l":
9732                     wrap.setSize(0, b.height);
9733                     st.right = st.top = "0";
9734                     a = {width: bw};
9735                 break;
9736                 case "r":
9737                     wrap.setSize(0, b.height);
9738                     wrap.setX(b.right);
9739                     st.left = st.top = "0";
9740                     a = {width: bw, points: pt};
9741                 break;
9742                 case "b":
9743                     wrap.setSize(b.width, 0);
9744                     wrap.setY(b.bottom);
9745                     st.left = st.top = "0";
9746                     a = {height: bh, points: pt};
9747                 break;
9748                 case "tl":
9749                     wrap.setSize(0, 0);
9750                     st.right = st.bottom = "0";
9751                     a = {width: bw, height: bh};
9752                 break;
9753                 case "bl":
9754                     wrap.setSize(0, 0);
9755                     wrap.setY(b.y+b.height);
9756                     st.right = st.top = "0";
9757                     a = {width: bw, height: bh, points: pt};
9758                 break;
9759                 case "br":
9760                     wrap.setSize(0, 0);
9761                     wrap.setXY([b.right, b.bottom]);
9762                     st.left = st.top = "0";
9763                     a = {width: bw, height: bh, points: pt};
9764                 break;
9765                 case "tr":
9766                     wrap.setSize(0, 0);
9767                     wrap.setX(b.x+b.width);
9768                     st.left = st.bottom = "0";
9769                     a = {width: bw, height: bh, points: pt};
9770                 break;
9771             }
9772             this.dom.style.visibility = "visible";
9773             wrap.show();
9774
9775             arguments.callee.anim = wrap.fxanim(a,
9776                 o,
9777                 'motion',
9778                 .5,
9779                 'easeOut', after);
9780         });
9781         return this;
9782     },
9783     
9784         /**
9785          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9786          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9787          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9788          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9789          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9790          * Usage:
9791          *<pre><code>
9792 // default: slide the element out to the top
9793 el.slideOut();
9794
9795 // custom: slide the element out to the right with a 2-second duration
9796 el.slideOut('r', { duration: 2 });
9797
9798 // common config options shown with default values
9799 el.slideOut('t', {
9800     easing: 'easeOut',
9801     duration: .5,
9802     remove: false,
9803     useDisplay: false
9804 });
9805 </code></pre>
9806          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9807          * @param {Object} options (optional) Object literal with any of the Fx config options
9808          * @return {Roo.Element} The Element
9809          */
9810     slideOut : function(anchor, o){
9811         var el = this.getFxEl();
9812         o = o || {};
9813
9814         el.queueFx(o, function(){
9815
9816             anchor = anchor || "t";
9817
9818             // restore values after effect
9819             var r = this.getFxRestore();
9820             
9821             var b = this.getBox();
9822             // fixed size for slide
9823             this.setSize(b);
9824
9825             // wrap if needed
9826             var wrap = this.fxWrap(r.pos, o, "visible");
9827
9828             var st = this.dom.style;
9829             st.visibility = "visible";
9830             st.position = "absolute";
9831
9832             wrap.setSize(b);
9833
9834             var after = function(){
9835                 if(o.useDisplay){
9836                     el.setDisplayed(false);
9837                 }else{
9838                     el.hide();
9839                 }
9840
9841                 el.fxUnwrap(wrap, r.pos, o);
9842
9843                 st.width = r.width;
9844                 st.height = r.height;
9845
9846                 el.afterFx(o);
9847             };
9848
9849             var a, zero = {to: 0};
9850             switch(anchor.toLowerCase()){
9851                 case "t":
9852                     st.left = st.bottom = "0";
9853                     a = {height: zero};
9854                 break;
9855                 case "l":
9856                     st.right = st.top = "0";
9857                     a = {width: zero};
9858                 break;
9859                 case "r":
9860                     st.left = st.top = "0";
9861                     a = {width: zero, points: {to:[b.right, b.y]}};
9862                 break;
9863                 case "b":
9864                     st.left = st.top = "0";
9865                     a = {height: zero, points: {to:[b.x, b.bottom]}};
9866                 break;
9867                 case "tl":
9868                     st.right = st.bottom = "0";
9869                     a = {width: zero, height: zero};
9870                 break;
9871                 case "bl":
9872                     st.right = st.top = "0";
9873                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9874                 break;
9875                 case "br":
9876                     st.left = st.top = "0";
9877                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9878                 break;
9879                 case "tr":
9880                     st.left = st.bottom = "0";
9881                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9882                 break;
9883             }
9884
9885             arguments.callee.anim = wrap.fxanim(a,
9886                 o,
9887                 'motion',
9888                 .5,
9889                 "easeOut", after);
9890         });
9891         return this;
9892     },
9893
9894         /**
9895          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
9896          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
9897          * The element must be removed from the DOM using the 'remove' config option if desired.
9898          * Usage:
9899          *<pre><code>
9900 // default
9901 el.puff();
9902
9903 // common config options shown with default values
9904 el.puff({
9905     easing: 'easeOut',
9906     duration: .5,
9907     remove: false,
9908     useDisplay: false
9909 });
9910 </code></pre>
9911          * @param {Object} options (optional) Object literal with any of the Fx config options
9912          * @return {Roo.Element} The Element
9913          */
9914     puff : function(o){
9915         var el = this.getFxEl();
9916         o = o || {};
9917
9918         el.queueFx(o, function(){
9919             this.clearOpacity();
9920             this.show();
9921
9922             // restore values after effect
9923             var r = this.getFxRestore();
9924             var st = this.dom.style;
9925
9926             var after = function(){
9927                 if(o.useDisplay){
9928                     el.setDisplayed(false);
9929                 }else{
9930                     el.hide();
9931                 }
9932
9933                 el.clearOpacity();
9934
9935                 el.setPositioning(r.pos);
9936                 st.width = r.width;
9937                 st.height = r.height;
9938                 st.fontSize = '';
9939                 el.afterFx(o);
9940             };
9941
9942             var width = this.getWidth();
9943             var height = this.getHeight();
9944
9945             arguments.callee.anim = this.fxanim({
9946                     width : {to: this.adjustWidth(width * 2)},
9947                     height : {to: this.adjustHeight(height * 2)},
9948                     points : {by: [-(width * .5), -(height * .5)]},
9949                     opacity : {to: 0},
9950                     fontSize: {to:200, unit: "%"}
9951                 },
9952                 o,
9953                 'motion',
9954                 .5,
9955                 "easeOut", after);
9956         });
9957         return this;
9958     },
9959
9960         /**
9961          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9962          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
9963          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9964          * Usage:
9965          *<pre><code>
9966 // default
9967 el.switchOff();
9968
9969 // all config options shown with default values
9970 el.switchOff({
9971     easing: 'easeIn',
9972     duration: .3,
9973     remove: false,
9974     useDisplay: false
9975 });
9976 </code></pre>
9977          * @param {Object} options (optional) Object literal with any of the Fx config options
9978          * @return {Roo.Element} The Element
9979          */
9980     switchOff : function(o){
9981         var el = this.getFxEl();
9982         o = o || {};
9983
9984         el.queueFx(o, function(){
9985             this.clearOpacity();
9986             this.clip();
9987
9988             // restore values after effect
9989             var r = this.getFxRestore();
9990             var st = this.dom.style;
9991
9992             var after = function(){
9993                 if(o.useDisplay){
9994                     el.setDisplayed(false);
9995                 }else{
9996                     el.hide();
9997                 }
9998
9999                 el.clearOpacity();
10000                 el.setPositioning(r.pos);
10001                 st.width = r.width;
10002                 st.height = r.height;
10003
10004                 el.afterFx(o);
10005             };
10006
10007             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10008                 this.clearOpacity();
10009                 (function(){
10010                     this.fxanim({
10011                         height:{to:1},
10012                         points:{by:[0, this.getHeight() * .5]}
10013                     }, o, 'motion', 0.3, 'easeIn', after);
10014                 }).defer(100, this);
10015             });
10016         });
10017         return this;
10018     },
10019
10020     /**
10021      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10022      * changed using the "attr" config option) and then fading back to the original color. If no original
10023      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10024      * Usage:
10025 <pre><code>
10026 // default: highlight background to yellow
10027 el.highlight();
10028
10029 // custom: highlight foreground text to blue for 2 seconds
10030 el.highlight("0000ff", { attr: 'color', duration: 2 });
10031
10032 // common config options shown with default values
10033 el.highlight("ffff9c", {
10034     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10035     endColor: (current color) or "ffffff",
10036     easing: 'easeIn',
10037     duration: 1
10038 });
10039 </code></pre>
10040      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10041      * @param {Object} options (optional) Object literal with any of the Fx config options
10042      * @return {Roo.Element} The Element
10043      */ 
10044     highlight : function(color, o){
10045         var el = this.getFxEl();
10046         o = o || {};
10047
10048         el.queueFx(o, function(){
10049             color = color || "ffff9c";
10050             attr = o.attr || "backgroundColor";
10051
10052             this.clearOpacity();
10053             this.show();
10054
10055             var origColor = this.getColor(attr);
10056             var restoreColor = this.dom.style[attr];
10057             endColor = (o.endColor || origColor) || "ffffff";
10058
10059             var after = function(){
10060                 el.dom.style[attr] = restoreColor;
10061                 el.afterFx(o);
10062             };
10063
10064             var a = {};
10065             a[attr] = {from: color, to: endColor};
10066             arguments.callee.anim = this.fxanim(a,
10067                 o,
10068                 'color',
10069                 1,
10070                 'easeIn', after);
10071         });
10072         return this;
10073     },
10074
10075    /**
10076     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10077     * Usage:
10078 <pre><code>
10079 // default: a single light blue ripple
10080 el.frame();
10081
10082 // custom: 3 red ripples lasting 3 seconds total
10083 el.frame("ff0000", 3, { duration: 3 });
10084
10085 // common config options shown with default values
10086 el.frame("C3DAF9", 1, {
10087     duration: 1 //duration of entire animation (not each individual ripple)
10088     // Note: Easing is not configurable and will be ignored if included
10089 });
10090 </code></pre>
10091     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10092     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10093     * @param {Object} options (optional) Object literal with any of the Fx config options
10094     * @return {Roo.Element} The Element
10095     */
10096     frame : function(color, count, o){
10097         var el = this.getFxEl();
10098         o = o || {};
10099
10100         el.queueFx(o, function(){
10101             color = color || "#C3DAF9";
10102             if(color.length == 6){
10103                 color = "#" + color;
10104             }
10105             count = count || 1;
10106             duration = o.duration || 1;
10107             this.show();
10108
10109             var b = this.getBox();
10110             var animFn = function(){
10111                 var proxy = this.createProxy({
10112
10113                      style:{
10114                         visbility:"hidden",
10115                         position:"absolute",
10116                         "z-index":"35000", // yee haw
10117                         border:"0px solid " + color
10118                      }
10119                   });
10120                 var scale = Roo.isBorderBox ? 2 : 1;
10121                 proxy.animate({
10122                     top:{from:b.y, to:b.y - 20},
10123                     left:{from:b.x, to:b.x - 20},
10124                     borderWidth:{from:0, to:10},
10125                     opacity:{from:1, to:0},
10126                     height:{from:b.height, to:(b.height + (20*scale))},
10127                     width:{from:b.width, to:(b.width + (20*scale))}
10128                 }, duration, function(){
10129                     proxy.remove();
10130                 });
10131                 if(--count > 0){
10132                      animFn.defer((duration/2)*1000, this);
10133                 }else{
10134                     el.afterFx(o);
10135                 }
10136             };
10137             animFn.call(this);
10138         });
10139         return this;
10140     },
10141
10142    /**
10143     * Creates a pause before any subsequent queued effects begin.  If there are
10144     * no effects queued after the pause it will have no effect.
10145     * Usage:
10146 <pre><code>
10147 el.pause(1);
10148 </code></pre>
10149     * @param {Number} seconds The length of time to pause (in seconds)
10150     * @return {Roo.Element} The Element
10151     */
10152     pause : function(seconds){
10153         var el = this.getFxEl();
10154         var o = {};
10155
10156         el.queueFx(o, function(){
10157             setTimeout(function(){
10158                 el.afterFx(o);
10159             }, seconds * 1000);
10160         });
10161         return this;
10162     },
10163
10164    /**
10165     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10166     * using the "endOpacity" config option.
10167     * Usage:
10168 <pre><code>
10169 // default: fade in from opacity 0 to 100%
10170 el.fadeIn();
10171
10172 // custom: fade in from opacity 0 to 75% over 2 seconds
10173 el.fadeIn({ endOpacity: .75, duration: 2});
10174
10175 // common config options shown with default values
10176 el.fadeIn({
10177     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10178     easing: 'easeOut',
10179     duration: .5
10180 });
10181 </code></pre>
10182     * @param {Object} options (optional) Object literal with any of the Fx config options
10183     * @return {Roo.Element} The Element
10184     */
10185     fadeIn : function(o){
10186         var el = this.getFxEl();
10187         o = o || {};
10188         el.queueFx(o, function(){
10189             this.setOpacity(0);
10190             this.fixDisplay();
10191             this.dom.style.visibility = 'visible';
10192             var to = o.endOpacity || 1;
10193             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10194                 o, null, .5, "easeOut", function(){
10195                 if(to == 1){
10196                     this.clearOpacity();
10197                 }
10198                 el.afterFx(o);
10199             });
10200         });
10201         return this;
10202     },
10203
10204    /**
10205     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10206     * using the "endOpacity" config option.
10207     * Usage:
10208 <pre><code>
10209 // default: fade out from the element's current opacity to 0
10210 el.fadeOut();
10211
10212 // custom: fade out from the element's current opacity to 25% over 2 seconds
10213 el.fadeOut({ endOpacity: .25, duration: 2});
10214
10215 // common config options shown with default values
10216 el.fadeOut({
10217     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10218     easing: 'easeOut',
10219     duration: .5
10220     remove: false,
10221     useDisplay: false
10222 });
10223 </code></pre>
10224     * @param {Object} options (optional) Object literal with any of the Fx config options
10225     * @return {Roo.Element} The Element
10226     */
10227     fadeOut : function(o){
10228         var el = this.getFxEl();
10229         o = o || {};
10230         el.queueFx(o, function(){
10231             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10232                 o, null, .5, "easeOut", function(){
10233                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10234                      this.dom.style.display = "none";
10235                 }else{
10236                      this.dom.style.visibility = "hidden";
10237                 }
10238                 this.clearOpacity();
10239                 el.afterFx(o);
10240             });
10241         });
10242         return this;
10243     },
10244
10245    /**
10246     * Animates the transition of an element's dimensions from a starting height/width
10247     * to an ending height/width.
10248     * Usage:
10249 <pre><code>
10250 // change height and width to 100x100 pixels
10251 el.scale(100, 100);
10252
10253 // common config options shown with default values.  The height and width will default to
10254 // the element's existing values if passed as null.
10255 el.scale(
10256     [element's width],
10257     [element's height], {
10258     easing: 'easeOut',
10259     duration: .35
10260 });
10261 </code></pre>
10262     * @param {Number} width  The new width (pass undefined to keep the original width)
10263     * @param {Number} height  The new height (pass undefined to keep the original height)
10264     * @param {Object} options (optional) Object literal with any of the Fx config options
10265     * @return {Roo.Element} The Element
10266     */
10267     scale : function(w, h, o){
10268         this.shift(Roo.apply({}, o, {
10269             width: w,
10270             height: h
10271         }));
10272         return this;
10273     },
10274
10275    /**
10276     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10277     * Any of these properties not specified in the config object will not be changed.  This effect 
10278     * requires that at least one new dimension, position or opacity setting must be passed in on
10279     * the config object in order for the function to have any effect.
10280     * Usage:
10281 <pre><code>
10282 // slide the element horizontally to x position 200 while changing the height and opacity
10283 el.shift({ x: 200, height: 50, opacity: .8 });
10284
10285 // common config options shown with default values.
10286 el.shift({
10287     width: [element's width],
10288     height: [element's height],
10289     x: [element's x position],
10290     y: [element's y position],
10291     opacity: [element's opacity],
10292     easing: 'easeOut',
10293     duration: .35
10294 });
10295 </code></pre>
10296     * @param {Object} options  Object literal with any of the Fx config options
10297     * @return {Roo.Element} The Element
10298     */
10299     shift : function(o){
10300         var el = this.getFxEl();
10301         o = o || {};
10302         el.queueFx(o, function(){
10303             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10304             if(w !== undefined){
10305                 a.width = {to: this.adjustWidth(w)};
10306             }
10307             if(h !== undefined){
10308                 a.height = {to: this.adjustHeight(h)};
10309             }
10310             if(x !== undefined || y !== undefined){
10311                 a.points = {to: [
10312                     x !== undefined ? x : this.getX(),
10313                     y !== undefined ? y : this.getY()
10314                 ]};
10315             }
10316             if(op !== undefined){
10317                 a.opacity = {to: op};
10318             }
10319             if(o.xy !== undefined){
10320                 a.points = {to: o.xy};
10321             }
10322             arguments.callee.anim = this.fxanim(a,
10323                 o, 'motion', .35, "easeOut", function(){
10324                 el.afterFx(o);
10325             });
10326         });
10327         return this;
10328     },
10329
10330         /**
10331          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10332          * ending point of the effect.
10333          * Usage:
10334          *<pre><code>
10335 // default: slide the element downward while fading out
10336 el.ghost();
10337
10338 // custom: slide the element out to the right with a 2-second duration
10339 el.ghost('r', { duration: 2 });
10340
10341 // common config options shown with default values
10342 el.ghost('b', {
10343     easing: 'easeOut',
10344     duration: .5
10345     remove: false,
10346     useDisplay: false
10347 });
10348 </code></pre>
10349          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10350          * @param {Object} options (optional) Object literal with any of the Fx config options
10351          * @return {Roo.Element} The Element
10352          */
10353     ghost : function(anchor, o){
10354         var el = this.getFxEl();
10355         o = o || {};
10356
10357         el.queueFx(o, function(){
10358             anchor = anchor || "b";
10359
10360             // restore values after effect
10361             var r = this.getFxRestore();
10362             var w = this.getWidth(),
10363                 h = this.getHeight();
10364
10365             var st = this.dom.style;
10366
10367             var after = function(){
10368                 if(o.useDisplay){
10369                     el.setDisplayed(false);
10370                 }else{
10371                     el.hide();
10372                 }
10373
10374                 el.clearOpacity();
10375                 el.setPositioning(r.pos);
10376                 st.width = r.width;
10377                 st.height = r.height;
10378
10379                 el.afterFx(o);
10380             };
10381
10382             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10383             switch(anchor.toLowerCase()){
10384                 case "t":
10385                     pt.by = [0, -h];
10386                 break;
10387                 case "l":
10388                     pt.by = [-w, 0];
10389                 break;
10390                 case "r":
10391                     pt.by = [w, 0];
10392                 break;
10393                 case "b":
10394                     pt.by = [0, h];
10395                 break;
10396                 case "tl":
10397                     pt.by = [-w, -h];
10398                 break;
10399                 case "bl":
10400                     pt.by = [-w, h];
10401                 break;
10402                 case "br":
10403                     pt.by = [w, h];
10404                 break;
10405                 case "tr":
10406                     pt.by = [w, -h];
10407                 break;
10408             }
10409
10410             arguments.callee.anim = this.fxanim(a,
10411                 o,
10412                 'motion',
10413                 .5,
10414                 "easeOut", after);
10415         });
10416         return this;
10417     },
10418
10419         /**
10420          * Ensures that all effects queued after syncFx is called on the element are
10421          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10422          * @return {Roo.Element} The Element
10423          */
10424     syncFx : function(){
10425         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10426             block : false,
10427             concurrent : true,
10428             stopFx : false
10429         });
10430         return this;
10431     },
10432
10433         /**
10434          * Ensures that all effects queued after sequenceFx is called on the element are
10435          * run in sequence.  This is the opposite of {@link #syncFx}.
10436          * @return {Roo.Element} The Element
10437          */
10438     sequenceFx : function(){
10439         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10440             block : false,
10441             concurrent : false,
10442             stopFx : false
10443         });
10444         return this;
10445     },
10446
10447         /* @private */
10448     nextFx : function(){
10449         var ef = this.fxQueue[0];
10450         if(ef){
10451             ef.call(this);
10452         }
10453     },
10454
10455         /**
10456          * Returns true if the element has any effects actively running or queued, else returns false.
10457          * @return {Boolean} True if element has active effects, else false
10458          */
10459     hasActiveFx : function(){
10460         return this.fxQueue && this.fxQueue[0];
10461     },
10462
10463         /**
10464          * Stops any running effects and clears the element's internal effects queue if it contains
10465          * any additional effects that haven't started yet.
10466          * @return {Roo.Element} The Element
10467          */
10468     stopFx : function(){
10469         if(this.hasActiveFx()){
10470             var cur = this.fxQueue[0];
10471             if(cur && cur.anim && cur.anim.isAnimated()){
10472                 this.fxQueue = [cur]; // clear out others
10473                 cur.anim.stop(true);
10474             }
10475         }
10476         return this;
10477     },
10478
10479         /* @private */
10480     beforeFx : function(o){
10481         if(this.hasActiveFx() && !o.concurrent){
10482            if(o.stopFx){
10483                this.stopFx();
10484                return true;
10485            }
10486            return false;
10487         }
10488         return true;
10489     },
10490
10491         /**
10492          * Returns true if the element is currently blocking so that no other effect can be queued
10493          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10494          * used to ensure that an effect initiated by a user action runs to completion prior to the
10495          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10496          * @return {Boolean} True if blocking, else false
10497          */
10498     hasFxBlock : function(){
10499         var q = this.fxQueue;
10500         return q && q[0] && q[0].block;
10501     },
10502
10503         /* @private */
10504     queueFx : function(o, fn){
10505         if(!this.fxQueue){
10506             this.fxQueue = [];
10507         }
10508         if(!this.hasFxBlock()){
10509             Roo.applyIf(o, this.fxDefaults);
10510             if(!o.concurrent){
10511                 var run = this.beforeFx(o);
10512                 fn.block = o.block;
10513                 this.fxQueue.push(fn);
10514                 if(run){
10515                     this.nextFx();
10516                 }
10517             }else{
10518                 fn.call(this);
10519             }
10520         }
10521         return this;
10522     },
10523
10524         /* @private */
10525     fxWrap : function(pos, o, vis){
10526         var wrap;
10527         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10528             var wrapXY;
10529             if(o.fixPosition){
10530                 wrapXY = this.getXY();
10531             }
10532             var div = document.createElement("div");
10533             div.style.visibility = vis;
10534             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10535             wrap.setPositioning(pos);
10536             if(wrap.getStyle("position") == "static"){
10537                 wrap.position("relative");
10538             }
10539             this.clearPositioning('auto');
10540             wrap.clip();
10541             wrap.dom.appendChild(this.dom);
10542             if(wrapXY){
10543                 wrap.setXY(wrapXY);
10544             }
10545         }
10546         return wrap;
10547     },
10548
10549         /* @private */
10550     fxUnwrap : function(wrap, pos, o){
10551         this.clearPositioning();
10552         this.setPositioning(pos);
10553         if(!o.wrap){
10554             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10555             wrap.remove();
10556         }
10557     },
10558
10559         /* @private */
10560     getFxRestore : function(){
10561         var st = this.dom.style;
10562         return {pos: this.getPositioning(), width: st.width, height : st.height};
10563     },
10564
10565         /* @private */
10566     afterFx : function(o){
10567         if(o.afterStyle){
10568             this.applyStyles(o.afterStyle);
10569         }
10570         if(o.afterCls){
10571             this.addClass(o.afterCls);
10572         }
10573         if(o.remove === true){
10574             this.remove();
10575         }
10576         Roo.callback(o.callback, o.scope, [this]);
10577         if(!o.concurrent){
10578             this.fxQueue.shift();
10579             this.nextFx();
10580         }
10581     },
10582
10583         /* @private */
10584     getFxEl : function(){ // support for composite element fx
10585         return Roo.get(this.dom);
10586     },
10587
10588         /* @private */
10589     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10590         animType = animType || 'run';
10591         opt = opt || {};
10592         var anim = Roo.lib.Anim[animType](
10593             this.dom, args,
10594             (opt.duration || defaultDur) || .35,
10595             (opt.easing || defaultEase) || 'easeOut',
10596             function(){
10597                 Roo.callback(cb, this);
10598             },
10599             this
10600         );
10601         opt.anim = anim;
10602         return anim;
10603     }
10604 };
10605
10606 // backwords compat
10607 Roo.Fx.resize = Roo.Fx.scale;
10608
10609 //When included, Roo.Fx is automatically applied to Element so that all basic
10610 //effects are available directly via the Element API
10611 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10612  * Based on:
10613  * Ext JS Library 1.1.1
10614  * Copyright(c) 2006-2007, Ext JS, LLC.
10615  *
10616  * Originally Released Under LGPL - original licence link has changed is not relivant.
10617  *
10618  * Fork - LGPL
10619  * <script type="text/javascript">
10620  */
10621
10622
10623 /**
10624  * @class Roo.CompositeElement
10625  * Standard composite class. Creates a Roo.Element for every element in the collection.
10626  * <br><br>
10627  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10628  * actions will be performed on all the elements in this collection.</b>
10629  * <br><br>
10630  * All methods return <i>this</i> and can be chained.
10631  <pre><code>
10632  var els = Roo.select("#some-el div.some-class", true);
10633  // or select directly from an existing element
10634  var el = Roo.get('some-el');
10635  el.select('div.some-class', true);
10636
10637  els.setWidth(100); // all elements become 100 width
10638  els.hide(true); // all elements fade out and hide
10639  // or
10640  els.setWidth(100).hide(true);
10641  </code></pre>
10642  */
10643 Roo.CompositeElement = function(els){
10644     this.elements = [];
10645     this.addElements(els);
10646 };
10647 Roo.CompositeElement.prototype = {
10648     isComposite: true,
10649     addElements : function(els){
10650         if(!els) return this;
10651         if(typeof els == "string"){
10652             els = Roo.Element.selectorFunction(els);
10653         }
10654         var yels = this.elements;
10655         var index = yels.length-1;
10656         for(var i = 0, len = els.length; i < len; i++) {
10657                 yels[++index] = Roo.get(els[i]);
10658         }
10659         return this;
10660     },
10661
10662     /**
10663     * Clears this composite and adds the elements returned by the passed selector.
10664     * @param {String/Array} els A string CSS selector, an array of elements or an element
10665     * @return {CompositeElement} this
10666     */
10667     fill : function(els){
10668         this.elements = [];
10669         this.add(els);
10670         return this;
10671     },
10672
10673     /**
10674     * Filters this composite to only elements that match the passed selector.
10675     * @param {String} selector A string CSS selector
10676     * @return {CompositeElement} this
10677     */
10678     filter : function(selector){
10679         var els = [];
10680         this.each(function(el){
10681             if(el.is(selector)){
10682                 els[els.length] = el.dom;
10683             }
10684         });
10685         this.fill(els);
10686         return this;
10687     },
10688
10689     invoke : function(fn, args){
10690         var els = this.elements;
10691         for(var i = 0, len = els.length; i < len; i++) {
10692                 Roo.Element.prototype[fn].apply(els[i], args);
10693         }
10694         return this;
10695     },
10696     /**
10697     * Adds elements to this composite.
10698     * @param {String/Array} els A string CSS selector, an array of elements or an element
10699     * @return {CompositeElement} this
10700     */
10701     add : function(els){
10702         if(typeof els == "string"){
10703             this.addElements(Roo.Element.selectorFunction(els));
10704         }else if(els.length !== undefined){
10705             this.addElements(els);
10706         }else{
10707             this.addElements([els]);
10708         }
10709         return this;
10710     },
10711     /**
10712     * Calls the passed function passing (el, this, index) for each element in this composite.
10713     * @param {Function} fn The function to call
10714     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10715     * @return {CompositeElement} this
10716     */
10717     each : function(fn, scope){
10718         var els = this.elements;
10719         for(var i = 0, len = els.length; i < len; i++){
10720             if(fn.call(scope || els[i], els[i], this, i) === false) {
10721                 break;
10722             }
10723         }
10724         return this;
10725     },
10726
10727     /**
10728      * Returns the Element object at the specified index
10729      * @param {Number} index
10730      * @return {Roo.Element}
10731      */
10732     item : function(index){
10733         return this.elements[index] || null;
10734     },
10735
10736     /**
10737      * Returns the first Element
10738      * @return {Roo.Element}
10739      */
10740     first : function(){
10741         return this.item(0);
10742     },
10743
10744     /**
10745      * Returns the last Element
10746      * @return {Roo.Element}
10747      */
10748     last : function(){
10749         return this.item(this.elements.length-1);
10750     },
10751
10752     /**
10753      * Returns the number of elements in this composite
10754      * @return Number
10755      */
10756     getCount : function(){
10757         return this.elements.length;
10758     },
10759
10760     /**
10761      * Returns true if this composite contains the passed element
10762      * @return Boolean
10763      */
10764     contains : function(el){
10765         return this.indexOf(el) !== -1;
10766     },
10767
10768     /**
10769      * Returns true if this composite contains the passed element
10770      * @return Boolean
10771      */
10772     indexOf : function(el){
10773         return this.elements.indexOf(Roo.get(el));
10774     },
10775
10776
10777     /**
10778     * Removes the specified element(s).
10779     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10780     * or an array of any of those.
10781     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10782     * @return {CompositeElement} this
10783     */
10784     removeElement : function(el, removeDom){
10785         if(el instanceof Array){
10786             for(var i = 0, len = el.length; i < len; i++){
10787                 this.removeElement(el[i]);
10788             }
10789             return this;
10790         }
10791         var index = typeof el == 'number' ? el : this.indexOf(el);
10792         if(index !== -1){
10793             if(removeDom){
10794                 var d = this.elements[index];
10795                 if(d.dom){
10796                     d.remove();
10797                 }else{
10798                     d.parentNode.removeChild(d);
10799                 }
10800             }
10801             this.elements.splice(index, 1);
10802         }
10803         return this;
10804     },
10805
10806     /**
10807     * Replaces the specified element with the passed element.
10808     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10809     * to replace.
10810     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10811     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10812     * @return {CompositeElement} this
10813     */
10814     replaceElement : function(el, replacement, domReplace){
10815         var index = typeof el == 'number' ? el : this.indexOf(el);
10816         if(index !== -1){
10817             if(domReplace){
10818                 this.elements[index].replaceWith(replacement);
10819             }else{
10820                 this.elements.splice(index, 1, Roo.get(replacement))
10821             }
10822         }
10823         return this;
10824     },
10825
10826     /**
10827      * Removes all elements.
10828      */
10829     clear : function(){
10830         this.elements = [];
10831     }
10832 };
10833 (function(){
10834     Roo.CompositeElement.createCall = function(proto, fnName){
10835         if(!proto[fnName]){
10836             proto[fnName] = function(){
10837                 return this.invoke(fnName, arguments);
10838             };
10839         }
10840     };
10841     for(var fnName in Roo.Element.prototype){
10842         if(typeof Roo.Element.prototype[fnName] == "function"){
10843             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10844         }
10845     };
10846 })();
10847 /*
10848  * Based on:
10849  * Ext JS Library 1.1.1
10850  * Copyright(c) 2006-2007, Ext JS, LLC.
10851  *
10852  * Originally Released Under LGPL - original licence link has changed is not relivant.
10853  *
10854  * Fork - LGPL
10855  * <script type="text/javascript">
10856  */
10857
10858 /**
10859  * @class Roo.CompositeElementLite
10860  * @extends Roo.CompositeElement
10861  * Flyweight composite class. Reuses the same Roo.Element for element operations.
10862  <pre><code>
10863  var els = Roo.select("#some-el div.some-class");
10864  // or select directly from an existing element
10865  var el = Roo.get('some-el');
10866  el.select('div.some-class');
10867
10868  els.setWidth(100); // all elements become 100 width
10869  els.hide(true); // all elements fade out and hide
10870  // or
10871  els.setWidth(100).hide(true);
10872  </code></pre><br><br>
10873  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10874  * actions will be performed on all the elements in this collection.</b>
10875  */
10876 Roo.CompositeElementLite = function(els){
10877     Roo.CompositeElementLite.superclass.constructor.call(this, els);
10878     this.el = new Roo.Element.Flyweight();
10879 };
10880 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10881     addElements : function(els){
10882         if(els){
10883             if(els instanceof Array){
10884                 this.elements = this.elements.concat(els);
10885             }else{
10886                 var yels = this.elements;
10887                 var index = yels.length-1;
10888                 for(var i = 0, len = els.length; i < len; i++) {
10889                     yels[++index] = els[i];
10890                 }
10891             }
10892         }
10893         return this;
10894     },
10895     invoke : function(fn, args){
10896         var els = this.elements;
10897         var el = this.el;
10898         for(var i = 0, len = els.length; i < len; i++) {
10899             el.dom = els[i];
10900                 Roo.Element.prototype[fn].apply(el, args);
10901         }
10902         return this;
10903     },
10904     /**
10905      * Returns a flyweight Element of the dom element object at the specified index
10906      * @param {Number} index
10907      * @return {Roo.Element}
10908      */
10909     item : function(index){
10910         if(!this.elements[index]){
10911             return null;
10912         }
10913         this.el.dom = this.elements[index];
10914         return this.el;
10915     },
10916
10917     // fixes scope with flyweight
10918     addListener : function(eventName, handler, scope, opt){
10919         var els = this.elements;
10920         for(var i = 0, len = els.length; i < len; i++) {
10921             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10922         }
10923         return this;
10924     },
10925
10926     /**
10927     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10928     * passed is the flyweight (shared) Roo.Element instance, so if you require a
10929     * a reference to the dom node, use el.dom.</b>
10930     * @param {Function} fn The function to call
10931     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10932     * @return {CompositeElement} this
10933     */
10934     each : function(fn, scope){
10935         var els = this.elements;
10936         var el = this.el;
10937         for(var i = 0, len = els.length; i < len; i++){
10938             el.dom = els[i];
10939                 if(fn.call(scope || el, el, this, i) === false){
10940                 break;
10941             }
10942         }
10943         return this;
10944     },
10945
10946     indexOf : function(el){
10947         return this.elements.indexOf(Roo.getDom(el));
10948     },
10949
10950     replaceElement : function(el, replacement, domReplace){
10951         var index = typeof el == 'number' ? el : this.indexOf(el);
10952         if(index !== -1){
10953             replacement = Roo.getDom(replacement);
10954             if(domReplace){
10955                 var d = this.elements[index];
10956                 d.parentNode.insertBefore(replacement, d);
10957                 d.parentNode.removeChild(d);
10958             }
10959             this.elements.splice(index, 1, replacement);
10960         }
10961         return this;
10962     }
10963 });
10964 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10965
10966 /*
10967  * Based on:
10968  * Ext JS Library 1.1.1
10969  * Copyright(c) 2006-2007, Ext JS, LLC.
10970  *
10971  * Originally Released Under LGPL - original licence link has changed is not relivant.
10972  *
10973  * Fork - LGPL
10974  * <script type="text/javascript">
10975  */
10976
10977  
10978
10979 /**
10980  * @class Roo.data.Connection
10981  * @extends Roo.util.Observable
10982  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10983  * either to a configured URL, or to a URL specified at request time.<br><br>
10984  * <p>
10985  * Requests made by this class are asynchronous, and will return immediately. No data from
10986  * the server will be available to the statement immediately following the {@link #request} call.
10987  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10988  * <p>
10989  * Note: If you are doing a file upload, you will not get a normal response object sent back to
10990  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10991  * The response object is created using the innerHTML of the IFRAME's document as the responseText
10992  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10993  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10994  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
10995  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10996  * standard DOM methods.
10997  * @constructor
10998  * @param {Object} config a configuration object.
10999  */
11000 Roo.data.Connection = function(config){
11001     Roo.apply(this, config);
11002     this.addEvents({
11003         /**
11004          * @event beforerequest
11005          * Fires before a network request is made to retrieve a data object.
11006          * @param {Connection} conn This Connection object.
11007          * @param {Object} options The options config object passed to the {@link #request} method.
11008          */
11009         "beforerequest" : true,
11010         /**
11011          * @event requestcomplete
11012          * Fires if the request was successfully completed.
11013          * @param {Connection} conn This Connection object.
11014          * @param {Object} response The XHR object containing the response data.
11015          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11016          * @param {Object} options The options config object passed to the {@link #request} method.
11017          */
11018         "requestcomplete" : true,
11019         /**
11020          * @event requestexception
11021          * Fires if an error HTTP status was returned from the server.
11022          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11023          * @param {Connection} conn This Connection object.
11024          * @param {Object} response The XHR object containing the response data.
11025          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11026          * @param {Object} options The options config object passed to the {@link #request} method.
11027          */
11028         "requestexception" : true
11029     });
11030     Roo.data.Connection.superclass.constructor.call(this);
11031 };
11032
11033 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11034     /**
11035      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11036      */
11037     /**
11038      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11039      * extra parameters to each request made by this object. (defaults to undefined)
11040      */
11041     /**
11042      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11043      *  to each request made by this object. (defaults to undefined)
11044      */
11045     /**
11046      * @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)
11047      */
11048     /**
11049      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11050      */
11051     timeout : 30000,
11052     /**
11053      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11054      * @type Boolean
11055      */
11056     autoAbort:false,
11057
11058     /**
11059      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11060      * @type Boolean
11061      */
11062     disableCaching: true,
11063
11064     /**
11065      * Sends an HTTP request to a remote server.
11066      * @param {Object} options An object which may contain the following properties:<ul>
11067      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11068      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11069      * request, a url encoded string or a function to call to get either.</li>
11070      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11071      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11072      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11073      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11074      * <li>options {Object} The parameter to the request call.</li>
11075      * <li>success {Boolean} True if the request succeeded.</li>
11076      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11077      * </ul></li>
11078      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11079      * The callback is passed the following parameters:<ul>
11080      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11081      * <li>options {Object} The parameter to the request call.</li>
11082      * </ul></li>
11083      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11084      * The callback is passed the following parameters:<ul>
11085      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11086      * <li>options {Object} The parameter to the request call.</li>
11087      * </ul></li>
11088      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11089      * for the callback function. Defaults to the browser window.</li>
11090      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11091      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11092      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11093      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11094      * params for the post data. Any params will be appended to the URL.</li>
11095      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11096      * </ul>
11097      * @return {Number} transactionId
11098      */
11099     request : function(o){
11100         if(this.fireEvent("beforerequest", this, o) !== false){
11101             var p = o.params;
11102
11103             if(typeof p == "function"){
11104                 p = p.call(o.scope||window, o);
11105             }
11106             if(typeof p == "object"){
11107                 p = Roo.urlEncode(o.params);
11108             }
11109             if(this.extraParams){
11110                 var extras = Roo.urlEncode(this.extraParams);
11111                 p = p ? (p + '&' + extras) : extras;
11112             }
11113
11114             var url = o.url || this.url;
11115             if(typeof url == 'function'){
11116                 url = url.call(o.scope||window, o);
11117             }
11118
11119             if(o.form){
11120                 var form = Roo.getDom(o.form);
11121                 url = url || form.action;
11122
11123                 var enctype = form.getAttribute("enctype");
11124                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11125                     return this.doFormUpload(o, p, url);
11126                 }
11127                 var f = Roo.lib.Ajax.serializeForm(form);
11128                 p = p ? (p + '&' + f) : f;
11129             }
11130
11131             var hs = o.headers;
11132             if(this.defaultHeaders){
11133                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11134                 if(!o.headers){
11135                     o.headers = hs;
11136                 }
11137             }
11138
11139             var cb = {
11140                 success: this.handleResponse,
11141                 failure: this.handleFailure,
11142                 scope: this,
11143                 argument: {options: o},
11144                 timeout : this.timeout
11145             };
11146
11147             var method = o.method||this.method||(p ? "POST" : "GET");
11148
11149             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11150                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11151             }
11152
11153             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11154                 if(o.autoAbort){
11155                     this.abort();
11156                 }
11157             }else if(this.autoAbort !== false){
11158                 this.abort();
11159             }
11160
11161             if((method == 'GET' && p) || o.xmlData){
11162                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11163                 p = '';
11164             }
11165             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11166             return this.transId;
11167         }else{
11168             Roo.callback(o.callback, o.scope, [o, null, null]);
11169             return null;
11170         }
11171     },
11172
11173     /**
11174      * Determine whether this object has a request outstanding.
11175      * @param {Number} transactionId (Optional) defaults to the last transaction
11176      * @return {Boolean} True if there is an outstanding request.
11177      */
11178     isLoading : function(transId){
11179         if(transId){
11180             return Roo.lib.Ajax.isCallInProgress(transId);
11181         }else{
11182             return this.transId ? true : false;
11183         }
11184     },
11185
11186     /**
11187      * Aborts any outstanding request.
11188      * @param {Number} transactionId (Optional) defaults to the last transaction
11189      */
11190     abort : function(transId){
11191         if(transId || this.isLoading()){
11192             Roo.lib.Ajax.abort(transId || this.transId);
11193         }
11194     },
11195
11196     // private
11197     handleResponse : function(response){
11198         this.transId = false;
11199         var options = response.argument.options;
11200         response.argument = options ? options.argument : null;
11201         this.fireEvent("requestcomplete", this, response, options);
11202         Roo.callback(options.success, options.scope, [response, options]);
11203         Roo.callback(options.callback, options.scope, [options, true, response]);
11204     },
11205
11206     // private
11207     handleFailure : function(response, e){
11208         this.transId = false;
11209         var options = response.argument.options;
11210         response.argument = options ? options.argument : null;
11211         this.fireEvent("requestexception", this, response, options, e);
11212         Roo.callback(options.failure, options.scope, [response, options]);
11213         Roo.callback(options.callback, options.scope, [options, false, response]);
11214     },
11215
11216     // private
11217     doFormUpload : function(o, ps, url){
11218         var id = Roo.id();
11219         var frame = document.createElement('iframe');
11220         frame.id = id;
11221         frame.name = id;
11222         frame.className = 'x-hidden';
11223         if(Roo.isIE){
11224             frame.src = Roo.SSL_SECURE_URL;
11225         }
11226         document.body.appendChild(frame);
11227
11228         if(Roo.isIE){
11229            document.frames[id].name = id;
11230         }
11231
11232         var form = Roo.getDom(o.form);
11233         form.target = id;
11234         form.method = 'POST';
11235         form.enctype = form.encoding = 'multipart/form-data';
11236         if(url){
11237             form.action = url;
11238         }
11239
11240         var hiddens, hd;
11241         if(ps){ // add dynamic params
11242             hiddens = [];
11243             ps = Roo.urlDecode(ps, false);
11244             for(var k in ps){
11245                 if(ps.hasOwnProperty(k)){
11246                     hd = document.createElement('input');
11247                     hd.type = 'hidden';
11248                     hd.name = k;
11249                     hd.value = ps[k];
11250                     form.appendChild(hd);
11251                     hiddens.push(hd);
11252                 }
11253             }
11254         }
11255
11256         function cb(){
11257             var r = {  // bogus response object
11258                 responseText : '',
11259                 responseXML : null
11260             };
11261
11262             r.argument = o ? o.argument : null;
11263
11264             try { //
11265                 var doc;
11266                 if(Roo.isIE){
11267                     doc = frame.contentWindow.document;
11268                 }else {
11269                     doc = (frame.contentDocument || window.frames[id].document);
11270                 }
11271                 if(doc && doc.body){
11272                     r.responseText = doc.body.innerHTML;
11273                 }
11274                 if(doc && doc.XMLDocument){
11275                     r.responseXML = doc.XMLDocument;
11276                 }else {
11277                     r.responseXML = doc;
11278                 }
11279             }
11280             catch(e) {
11281                 // ignore
11282             }
11283
11284             Roo.EventManager.removeListener(frame, 'load', cb, this);
11285
11286             this.fireEvent("requestcomplete", this, r, o);
11287             Roo.callback(o.success, o.scope, [r, o]);
11288             Roo.callback(o.callback, o.scope, [o, true, r]);
11289
11290             setTimeout(function(){document.body.removeChild(frame);}, 100);
11291         }
11292
11293         Roo.EventManager.on(frame, 'load', cb, this);
11294         form.submit();
11295
11296         if(hiddens){ // remove dynamic params
11297             for(var i = 0, len = hiddens.length; i < len; i++){
11298                 form.removeChild(hiddens[i]);
11299             }
11300         }
11301     }
11302 });
11303
11304 /**
11305  * @class Roo.Ajax
11306  * @extends Roo.data.Connection
11307  * Global Ajax request class.
11308  *
11309  * @singleton
11310  */
11311 Roo.Ajax = new Roo.data.Connection({
11312     // fix up the docs
11313    /**
11314      * @cfg {String} url @hide
11315      */
11316     /**
11317      * @cfg {Object} extraParams @hide
11318      */
11319     /**
11320      * @cfg {Object} defaultHeaders @hide
11321      */
11322     /**
11323      * @cfg {String} method (Optional) @hide
11324      */
11325     /**
11326      * @cfg {Number} timeout (Optional) @hide
11327      */
11328     /**
11329      * @cfg {Boolean} autoAbort (Optional) @hide
11330      */
11331
11332     /**
11333      * @cfg {Boolean} disableCaching (Optional) @hide
11334      */
11335
11336     /**
11337      * @property  disableCaching
11338      * True to add a unique cache-buster param to GET requests. (defaults to true)
11339      * @type Boolean
11340      */
11341     /**
11342      * @property  url
11343      * The default URL to be used for requests to the server. (defaults to undefined)
11344      * @type String
11345      */
11346     /**
11347      * @property  extraParams
11348      * An object containing properties which are used as
11349      * extra parameters to each request made by this object. (defaults to undefined)
11350      * @type Object
11351      */
11352     /**
11353      * @property  defaultHeaders
11354      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11355      * @type Object
11356      */
11357     /**
11358      * @property  method
11359      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11360      * @type String
11361      */
11362     /**
11363      * @property  timeout
11364      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11365      * @type Number
11366      */
11367
11368     /**
11369      * @property  autoAbort
11370      * Whether a new request should abort any pending requests. (defaults to false)
11371      * @type Boolean
11372      */
11373     autoAbort : false,
11374
11375     /**
11376      * Serialize the passed form into a url encoded string
11377      * @param {String/HTMLElement} form
11378      * @return {String}
11379      */
11380     serializeForm : function(form){
11381         return Roo.lib.Ajax.serializeForm(form);
11382     }
11383 });/*
11384  * Based on:
11385  * Ext JS Library 1.1.1
11386  * Copyright(c) 2006-2007, Ext JS, LLC.
11387  *
11388  * Originally Released Under LGPL - original licence link has changed is not relivant.
11389  *
11390  * Fork - LGPL
11391  * <script type="text/javascript">
11392  */
11393  
11394 /**
11395  * @class Roo.Ajax
11396  * @extends Roo.data.Connection
11397  * Global Ajax request class.
11398  *
11399  * @instanceOf  Roo.data.Connection
11400  */
11401 Roo.Ajax = new Roo.data.Connection({
11402     // fix up the docs
11403     
11404     /**
11405      * fix up scoping
11406      * @scope Roo.Ajax
11407      */
11408     
11409    /**
11410      * @cfg {String} url @hide
11411      */
11412     /**
11413      * @cfg {Object} extraParams @hide
11414      */
11415     /**
11416      * @cfg {Object} defaultHeaders @hide
11417      */
11418     /**
11419      * @cfg {String} method (Optional) @hide
11420      */
11421     /**
11422      * @cfg {Number} timeout (Optional) @hide
11423      */
11424     /**
11425      * @cfg {Boolean} autoAbort (Optional) @hide
11426      */
11427
11428     /**
11429      * @cfg {Boolean} disableCaching (Optional) @hide
11430      */
11431
11432     /**
11433      * @property  disableCaching
11434      * True to add a unique cache-buster param to GET requests. (defaults to true)
11435      * @type Boolean
11436      */
11437     /**
11438      * @property  url
11439      * The default URL to be used for requests to the server. (defaults to undefined)
11440      * @type String
11441      */
11442     /**
11443      * @property  extraParams
11444      * An object containing properties which are used as
11445      * extra parameters to each request made by this object. (defaults to undefined)
11446      * @type Object
11447      */
11448     /**
11449      * @property  defaultHeaders
11450      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11451      * @type Object
11452      */
11453     /**
11454      * @property  method
11455      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11456      * @type String
11457      */
11458     /**
11459      * @property  timeout
11460      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11461      * @type Number
11462      */
11463
11464     /**
11465      * @property  autoAbort
11466      * Whether a new request should abort any pending requests. (defaults to false)
11467      * @type Boolean
11468      */
11469     autoAbort : false,
11470
11471     /**
11472      * Serialize the passed form into a url encoded string
11473      * @param {String/HTMLElement} form
11474      * @return {String}
11475      */
11476     serializeForm : function(form){
11477         return Roo.lib.Ajax.serializeForm(form);
11478     }
11479 });/*
11480  * Based on:
11481  * Ext JS Library 1.1.1
11482  * Copyright(c) 2006-2007, Ext JS, LLC.
11483  *
11484  * Originally Released Under LGPL - original licence link has changed is not relivant.
11485  *
11486  * Fork - LGPL
11487  * <script type="text/javascript">
11488  */
11489
11490  
11491 /**
11492  * @class Roo.UpdateManager
11493  * @extends Roo.util.Observable
11494  * Provides AJAX-style update for Element object.<br><br>
11495  * Usage:<br>
11496  * <pre><code>
11497  * // Get it from a Roo.Element object
11498  * var el = Roo.get("foo");
11499  * var mgr = el.getUpdateManager();
11500  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11501  * ...
11502  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11503  * <br>
11504  * // or directly (returns the same UpdateManager instance)
11505  * var mgr = new Roo.UpdateManager("myElementId");
11506  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11507  * mgr.on("update", myFcnNeedsToKnow);
11508  * <br>
11509    // short handed call directly from the element object
11510    Roo.get("foo").load({
11511         url: "bar.php",
11512         scripts:true,
11513         params: "for=bar",
11514         text: "Loading Foo..."
11515    });
11516  * </code></pre>
11517  * @constructor
11518  * Create new UpdateManager directly.
11519  * @param {String/HTMLElement/Roo.Element} el The element to update
11520  * @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).
11521  */
11522 Roo.UpdateManager = function(el, forceNew){
11523     el = Roo.get(el);
11524     if(!forceNew && el.updateManager){
11525         return el.updateManager;
11526     }
11527     /**
11528      * The Element object
11529      * @type Roo.Element
11530      */
11531     this.el = el;
11532     /**
11533      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11534      * @type String
11535      */
11536     this.defaultUrl = null;
11537
11538     this.addEvents({
11539         /**
11540          * @event beforeupdate
11541          * Fired before an update is made, return false from your handler and the update is cancelled.
11542          * @param {Roo.Element} el
11543          * @param {String/Object/Function} url
11544          * @param {String/Object} params
11545          */
11546         "beforeupdate": true,
11547         /**
11548          * @event update
11549          * Fired after successful update is made.
11550          * @param {Roo.Element} el
11551          * @param {Object} oResponseObject The response Object
11552          */
11553         "update": true,
11554         /**
11555          * @event failure
11556          * Fired on update failure.
11557          * @param {Roo.Element} el
11558          * @param {Object} oResponseObject The response Object
11559          */
11560         "failure": true
11561     });
11562     var d = Roo.UpdateManager.defaults;
11563     /**
11564      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11565      * @type String
11566      */
11567     this.sslBlankUrl = d.sslBlankUrl;
11568     /**
11569      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11570      * @type Boolean
11571      */
11572     this.disableCaching = d.disableCaching;
11573     /**
11574      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11575      * @type String
11576      */
11577     this.indicatorText = d.indicatorText;
11578     /**
11579      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11580      * @type String
11581      */
11582     this.showLoadIndicator = d.showLoadIndicator;
11583     /**
11584      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11585      * @type Number
11586      */
11587     this.timeout = d.timeout;
11588
11589     /**
11590      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11591      * @type Boolean
11592      */
11593     this.loadScripts = d.loadScripts;
11594
11595     /**
11596      * Transaction object of current executing transaction
11597      */
11598     this.transaction = null;
11599
11600     /**
11601      * @private
11602      */
11603     this.autoRefreshProcId = null;
11604     /**
11605      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11606      * @type Function
11607      */
11608     this.refreshDelegate = this.refresh.createDelegate(this);
11609     /**
11610      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11611      * @type Function
11612      */
11613     this.updateDelegate = this.update.createDelegate(this);
11614     /**
11615      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11616      * @type Function
11617      */
11618     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11619     /**
11620      * @private
11621      */
11622     this.successDelegate = this.processSuccess.createDelegate(this);
11623     /**
11624      * @private
11625      */
11626     this.failureDelegate = this.processFailure.createDelegate(this);
11627
11628     if(!this.renderer){
11629      /**
11630       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11631       */
11632     this.renderer = new Roo.UpdateManager.BasicRenderer();
11633     }
11634     
11635     Roo.UpdateManager.superclass.constructor.call(this);
11636 };
11637
11638 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11639     /**
11640      * Get the Element this UpdateManager is bound to
11641      * @return {Roo.Element} The element
11642      */
11643     getEl : function(){
11644         return this.el;
11645     },
11646     /**
11647      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11648      * @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:
11649 <pre><code>
11650 um.update({<br/>
11651     url: "your-url.php",<br/>
11652     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11653     callback: yourFunction,<br/>
11654     scope: yourObject, //(optional scope)  <br/>
11655     discardUrl: false, <br/>
11656     nocache: false,<br/>
11657     text: "Loading...",<br/>
11658     timeout: 30,<br/>
11659     scripts: false<br/>
11660 });
11661 </code></pre>
11662      * The only required property is url. The optional properties nocache, text and scripts
11663      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11664      * @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}
11665      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11666      * @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.
11667      */
11668     update : function(url, params, callback, discardUrl){
11669         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11670             var method = this.method, cfg;
11671             if(typeof url == "object"){ // must be config object
11672                 cfg = url;
11673                 url = cfg.url;
11674                 params = params || cfg.params;
11675                 callback = callback || cfg.callback;
11676                 discardUrl = discardUrl || cfg.discardUrl;
11677                 if(callback && cfg.scope){
11678                     callback = callback.createDelegate(cfg.scope);
11679                 }
11680                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11681                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11682                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11683                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11684                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11685             }
11686             this.showLoading();
11687             if(!discardUrl){
11688                 this.defaultUrl = url;
11689             }
11690             if(typeof url == "function"){
11691                 url = url.call(this);
11692             }
11693
11694             method = method || (params ? "POST" : "GET");
11695             if(method == "GET"){
11696                 url = this.prepareUrl(url);
11697             }
11698
11699             var o = Roo.apply(cfg ||{}, {
11700                 url : url,
11701                 params: params,
11702                 success: this.successDelegate,
11703                 failure: this.failureDelegate,
11704                 callback: undefined,
11705                 timeout: (this.timeout*1000),
11706                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11707             });
11708
11709             this.transaction = Roo.Ajax.request(o);
11710         }
11711     },
11712
11713     /**
11714      * 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.
11715      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11716      * @param {String/HTMLElement} form The form Id or form element
11717      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11718      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11719      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11720      */
11721     formUpdate : function(form, url, reset, callback){
11722         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11723             if(typeof url == "function"){
11724                 url = url.call(this);
11725             }
11726             form = Roo.getDom(form);
11727             this.transaction = Roo.Ajax.request({
11728                 form: form,
11729                 url:url,
11730                 success: this.successDelegate,
11731                 failure: this.failureDelegate,
11732                 timeout: (this.timeout*1000),
11733                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11734             });
11735             this.showLoading.defer(1, this);
11736         }
11737     },
11738
11739     /**
11740      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11741      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11742      */
11743     refresh : function(callback){
11744         if(this.defaultUrl == null){
11745             return;
11746         }
11747         this.update(this.defaultUrl, null, callback, true);
11748     },
11749
11750     /**
11751      * Set this element to auto refresh.
11752      * @param {Number} interval How often to update (in seconds).
11753      * @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)
11754      * @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}
11755      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11756      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11757      */
11758     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11759         if(refreshNow){
11760             this.update(url || this.defaultUrl, params, callback, true);
11761         }
11762         if(this.autoRefreshProcId){
11763             clearInterval(this.autoRefreshProcId);
11764         }
11765         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11766     },
11767
11768     /**
11769      * Stop auto refresh on this element.
11770      */
11771      stopAutoRefresh : function(){
11772         if(this.autoRefreshProcId){
11773             clearInterval(this.autoRefreshProcId);
11774             delete this.autoRefreshProcId;
11775         }
11776     },
11777
11778     isAutoRefreshing : function(){
11779        return this.autoRefreshProcId ? true : false;
11780     },
11781     /**
11782      * Called to update the element to "Loading" state. Override to perform custom action.
11783      */
11784     showLoading : function(){
11785         if(this.showLoadIndicator){
11786             this.el.update(this.indicatorText);
11787         }
11788     },
11789
11790     /**
11791      * Adds unique parameter to query string if disableCaching = true
11792      * @private
11793      */
11794     prepareUrl : function(url){
11795         if(this.disableCaching){
11796             var append = "_dc=" + (new Date().getTime());
11797             if(url.indexOf("?") !== -1){
11798                 url += "&" + append;
11799             }else{
11800                 url += "?" + append;
11801             }
11802         }
11803         return url;
11804     },
11805
11806     /**
11807      * @private
11808      */
11809     processSuccess : function(response){
11810         this.transaction = null;
11811         if(response.argument.form && response.argument.reset){
11812             try{ // put in try/catch since some older FF releases had problems with this
11813                 response.argument.form.reset();
11814             }catch(e){}
11815         }
11816         if(this.loadScripts){
11817             this.renderer.render(this.el, response, this,
11818                 this.updateComplete.createDelegate(this, [response]));
11819         }else{
11820             this.renderer.render(this.el, response, this);
11821             this.updateComplete(response);
11822         }
11823     },
11824
11825     updateComplete : function(response){
11826         this.fireEvent("update", this.el, response);
11827         if(typeof response.argument.callback == "function"){
11828             response.argument.callback(this.el, true, response);
11829         }
11830     },
11831
11832     /**
11833      * @private
11834      */
11835     processFailure : function(response){
11836         this.transaction = null;
11837         this.fireEvent("failure", this.el, response);
11838         if(typeof response.argument.callback == "function"){
11839             response.argument.callback(this.el, false, response);
11840         }
11841     },
11842
11843     /**
11844      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11845      * @param {Object} renderer The object implementing the render() method
11846      */
11847     setRenderer : function(renderer){
11848         this.renderer = renderer;
11849     },
11850
11851     getRenderer : function(){
11852        return this.renderer;
11853     },
11854
11855     /**
11856      * Set the defaultUrl used for updates
11857      * @param {String/Function} defaultUrl The url or a function to call to get the url
11858      */
11859     setDefaultUrl : function(defaultUrl){
11860         this.defaultUrl = defaultUrl;
11861     },
11862
11863     /**
11864      * Aborts the executing transaction
11865      */
11866     abort : function(){
11867         if(this.transaction){
11868             Roo.Ajax.abort(this.transaction);
11869         }
11870     },
11871
11872     /**
11873      * Returns true if an update is in progress
11874      * @return {Boolean}
11875      */
11876     isUpdating : function(){
11877         if(this.transaction){
11878             return Roo.Ajax.isLoading(this.transaction);
11879         }
11880         return false;
11881     }
11882 });
11883
11884 /**
11885  * @class Roo.UpdateManager.defaults
11886  * @static (not really - but it helps the doc tool)
11887  * The defaults collection enables customizing the default properties of UpdateManager
11888  */
11889    Roo.UpdateManager.defaults = {
11890        /**
11891          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11892          * @type Number
11893          */
11894          timeout : 30,
11895
11896          /**
11897          * True to process scripts by default (Defaults to false).
11898          * @type Boolean
11899          */
11900         loadScripts : false,
11901
11902         /**
11903         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11904         * @type String
11905         */
11906         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11907         /**
11908          * Whether to append unique parameter on get request to disable caching (Defaults to false).
11909          * @type Boolean
11910          */
11911         disableCaching : false,
11912         /**
11913          * Whether to show indicatorText when loading (Defaults to true).
11914          * @type Boolean
11915          */
11916         showLoadIndicator : true,
11917         /**
11918          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11919          * @type String
11920          */
11921         indicatorText : '<div class="loading-indicator">Loading...</div>'
11922    };
11923
11924 /**
11925  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11926  *Usage:
11927  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11928  * @param {String/HTMLElement/Roo.Element} el The element to update
11929  * @param {String} url The url
11930  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11931  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11932  * @static
11933  * @deprecated
11934  * @member Roo.UpdateManager
11935  */
11936 Roo.UpdateManager.updateElement = function(el, url, params, options){
11937     var um = Roo.get(el, true).getUpdateManager();
11938     Roo.apply(um, options);
11939     um.update(url, params, options ? options.callback : null);
11940 };
11941 // alias for backwards compat
11942 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11943 /**
11944  * @class Roo.UpdateManager.BasicRenderer
11945  * Default Content renderer. Updates the elements innerHTML with the responseText.
11946  */
11947 Roo.UpdateManager.BasicRenderer = function(){};
11948
11949 Roo.UpdateManager.BasicRenderer.prototype = {
11950     /**
11951      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11952      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11953      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11954      * @param {Roo.Element} el The element being rendered
11955      * @param {Object} response The YUI Connect response object
11956      * @param {UpdateManager} updateManager The calling update manager
11957      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11958      */
11959      render : function(el, response, updateManager, callback){
11960         el.update(response.responseText, updateManager.loadScripts, callback);
11961     }
11962 };
11963 /*
11964  * Based on:
11965  * Ext JS Library 1.1.1
11966  * Copyright(c) 2006-2007, Ext JS, LLC.
11967  *
11968  * Originally Released Under LGPL - original licence link has changed is not relivant.
11969  *
11970  * Fork - LGPL
11971  * <script type="text/javascript">
11972  */
11973
11974 /**
11975  * @class Roo.util.DelayedTask
11976  * Provides a convenient method of performing setTimeout where a new
11977  * timeout cancels the old timeout. An example would be performing validation on a keypress.
11978  * You can use this class to buffer
11979  * the keypress events for a certain number of milliseconds, and perform only if they stop
11980  * for that amount of time.
11981  * @constructor The parameters to this constructor serve as defaults and are not required.
11982  * @param {Function} fn (optional) The default function to timeout
11983  * @param {Object} scope (optional) The default scope of that timeout
11984  * @param {Array} args (optional) The default Array of arguments
11985  */
11986 Roo.util.DelayedTask = function(fn, scope, args){
11987     var id = null, d, t;
11988
11989     var call = function(){
11990         var now = new Date().getTime();
11991         if(now - t >= d){
11992             clearInterval(id);
11993             id = null;
11994             fn.apply(scope, args || []);
11995         }
11996     };
11997     /**
11998      * Cancels any pending timeout and queues a new one
11999      * @param {Number} delay The milliseconds to delay
12000      * @param {Function} newFn (optional) Overrides function passed to constructor
12001      * @param {Object} newScope (optional) Overrides scope passed to constructor
12002      * @param {Array} newArgs (optional) Overrides args passed to constructor
12003      */
12004     this.delay = function(delay, newFn, newScope, newArgs){
12005         if(id && delay != d){
12006             this.cancel();
12007         }
12008         d = delay;
12009         t = new Date().getTime();
12010         fn = newFn || fn;
12011         scope = newScope || scope;
12012         args = newArgs || args;
12013         if(!id){
12014             id = setInterval(call, d);
12015         }
12016     };
12017
12018     /**
12019      * Cancel the last queued timeout
12020      */
12021     this.cancel = function(){
12022         if(id){
12023             clearInterval(id);
12024             id = null;
12025         }
12026     };
12027 };/*
12028  * Based on:
12029  * Ext JS Library 1.1.1
12030  * Copyright(c) 2006-2007, Ext JS, LLC.
12031  *
12032  * Originally Released Under LGPL - original licence link has changed is not relivant.
12033  *
12034  * Fork - LGPL
12035  * <script type="text/javascript">
12036  */
12037  
12038  
12039 Roo.util.TaskRunner = function(interval){
12040     interval = interval || 10;
12041     var tasks = [], removeQueue = [];
12042     var id = 0;
12043     var running = false;
12044
12045     var stopThread = function(){
12046         running = false;
12047         clearInterval(id);
12048         id = 0;
12049     };
12050
12051     var startThread = function(){
12052         if(!running){
12053             running = true;
12054             id = setInterval(runTasks, interval);
12055         }
12056     };
12057
12058     var removeTask = function(task){
12059         removeQueue.push(task);
12060         if(task.onStop){
12061             task.onStop();
12062         }
12063     };
12064
12065     var runTasks = function(){
12066         if(removeQueue.length > 0){
12067             for(var i = 0, len = removeQueue.length; i < len; i++){
12068                 tasks.remove(removeQueue[i]);
12069             }
12070             removeQueue = [];
12071             if(tasks.length < 1){
12072                 stopThread();
12073                 return;
12074             }
12075         }
12076         var now = new Date().getTime();
12077         for(var i = 0, len = tasks.length; i < len; ++i){
12078             var t = tasks[i];
12079             var itime = now - t.taskRunTime;
12080             if(t.interval <= itime){
12081                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12082                 t.taskRunTime = now;
12083                 if(rt === false || t.taskRunCount === t.repeat){
12084                     removeTask(t);
12085                     return;
12086                 }
12087             }
12088             if(t.duration && t.duration <= (now - t.taskStartTime)){
12089                 removeTask(t);
12090             }
12091         }
12092     };
12093
12094     /**
12095      * Queues a new task.
12096      * @param {Object} task
12097      */
12098     this.start = function(task){
12099         tasks.push(task);
12100         task.taskStartTime = new Date().getTime();
12101         task.taskRunTime = 0;
12102         task.taskRunCount = 0;
12103         startThread();
12104         return task;
12105     };
12106
12107     this.stop = function(task){
12108         removeTask(task);
12109         return task;
12110     };
12111
12112     this.stopAll = function(){
12113         stopThread();
12114         for(var i = 0, len = tasks.length; i < len; i++){
12115             if(tasks[i].onStop){
12116                 tasks[i].onStop();
12117             }
12118         }
12119         tasks = [];
12120         removeQueue = [];
12121     };
12122 };
12123
12124 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12125  * Based on:
12126  * Ext JS Library 1.1.1
12127  * Copyright(c) 2006-2007, Ext JS, LLC.
12128  *
12129  * Originally Released Under LGPL - original licence link has changed is not relivant.
12130  *
12131  * Fork - LGPL
12132  * <script type="text/javascript">
12133  */
12134
12135  
12136 /**
12137  * @class Roo.util.MixedCollection
12138  * @extends Roo.util.Observable
12139  * A Collection class that maintains both numeric indexes and keys and exposes events.
12140  * @constructor
12141  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12142  * collection (defaults to false)
12143  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12144  * and return the key value for that item.  This is used when available to look up the key on items that
12145  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12146  * equivalent to providing an implementation for the {@link #getKey} method.
12147  */
12148 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12149     this.items = [];
12150     this.map = {};
12151     this.keys = [];
12152     this.length = 0;
12153     this.addEvents({
12154         /**
12155          * @event clear
12156          * Fires when the collection is cleared.
12157          */
12158         "clear" : true,
12159         /**
12160          * @event add
12161          * Fires when an item is added to the collection.
12162          * @param {Number} index The index at which the item was added.
12163          * @param {Object} o The item added.
12164          * @param {String} key The key associated with the added item.
12165          */
12166         "add" : true,
12167         /**
12168          * @event replace
12169          * Fires when an item is replaced in the collection.
12170          * @param {String} key he key associated with the new added.
12171          * @param {Object} old The item being replaced.
12172          * @param {Object} new The new item.
12173          */
12174         "replace" : true,
12175         /**
12176          * @event remove
12177          * Fires when an item is removed from the collection.
12178          * @param {Object} o The item being removed.
12179          * @param {String} key (optional) The key associated with the removed item.
12180          */
12181         "remove" : true,
12182         "sort" : true
12183     });
12184     this.allowFunctions = allowFunctions === true;
12185     if(keyFn){
12186         this.getKey = keyFn;
12187     }
12188     Roo.util.MixedCollection.superclass.constructor.call(this);
12189 };
12190
12191 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12192     allowFunctions : false,
12193     
12194 /**
12195  * Adds an item to the collection.
12196  * @param {String} key The key to associate with the item
12197  * @param {Object} o The item to add.
12198  * @return {Object} The item added.
12199  */
12200     add : function(key, o){
12201         if(arguments.length == 1){
12202             o = arguments[0];
12203             key = this.getKey(o);
12204         }
12205         if(typeof key == "undefined" || key === null){
12206             this.length++;
12207             this.items.push(o);
12208             this.keys.push(null);
12209         }else{
12210             var old = this.map[key];
12211             if(old){
12212                 return this.replace(key, o);
12213             }
12214             this.length++;
12215             this.items.push(o);
12216             this.map[key] = o;
12217             this.keys.push(key);
12218         }
12219         this.fireEvent("add", this.length-1, o, key);
12220         return o;
12221     },
12222    
12223 /**
12224   * MixedCollection has a generic way to fetch keys if you implement getKey.
12225 <pre><code>
12226 // normal way
12227 var mc = new Roo.util.MixedCollection();
12228 mc.add(someEl.dom.id, someEl);
12229 mc.add(otherEl.dom.id, otherEl);
12230 //and so on
12231
12232 // using getKey
12233 var mc = new Roo.util.MixedCollection();
12234 mc.getKey = function(el){
12235    return el.dom.id;
12236 };
12237 mc.add(someEl);
12238 mc.add(otherEl);
12239
12240 // or via the constructor
12241 var mc = new Roo.util.MixedCollection(false, function(el){
12242    return el.dom.id;
12243 });
12244 mc.add(someEl);
12245 mc.add(otherEl);
12246 </code></pre>
12247  * @param o {Object} The item for which to find the key.
12248  * @return {Object} The key for the passed item.
12249  */
12250     getKey : function(o){
12251          return o.id; 
12252     },
12253    
12254 /**
12255  * Replaces an item in the collection.
12256  * @param {String} key The key associated with the item to replace, or the item to replace.
12257  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12258  * @return {Object}  The new item.
12259  */
12260     replace : function(key, o){
12261         if(arguments.length == 1){
12262             o = arguments[0];
12263             key = this.getKey(o);
12264         }
12265         var old = this.item(key);
12266         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12267              return this.add(key, o);
12268         }
12269         var index = this.indexOfKey(key);
12270         this.items[index] = o;
12271         this.map[key] = o;
12272         this.fireEvent("replace", key, old, o);
12273         return o;
12274     },
12275    
12276 /**
12277  * Adds all elements of an Array or an Object to the collection.
12278  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12279  * an Array of values, each of which are added to the collection.
12280  */
12281     addAll : function(objs){
12282         if(arguments.length > 1 || objs instanceof Array){
12283             var args = arguments.length > 1 ? arguments : objs;
12284             for(var i = 0, len = args.length; i < len; i++){
12285                 this.add(args[i]);
12286             }
12287         }else{
12288             for(var key in objs){
12289                 if(this.allowFunctions || typeof objs[key] != "function"){
12290                     this.add(key, objs[key]);
12291                 }
12292             }
12293         }
12294     },
12295    
12296 /**
12297  * Executes the specified function once for every item in the collection, passing each
12298  * item as the first and only parameter. returning false from the function will stop the iteration.
12299  * @param {Function} fn The function to execute for each item.
12300  * @param {Object} scope (optional) The scope in which to execute the function.
12301  */
12302     each : function(fn, scope){
12303         var items = [].concat(this.items); // each safe for removal
12304         for(var i = 0, len = items.length; i < len; i++){
12305             if(fn.call(scope || items[i], items[i], i, len) === false){
12306                 break;
12307             }
12308         }
12309     },
12310    
12311 /**
12312  * Executes the specified function once for every key in the collection, passing each
12313  * key, and its associated item as the first two parameters.
12314  * @param {Function} fn The function to execute for each item.
12315  * @param {Object} scope (optional) The scope in which to execute the function.
12316  */
12317     eachKey : function(fn, scope){
12318         for(var i = 0, len = this.keys.length; i < len; i++){
12319             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12320         }
12321     },
12322    
12323 /**
12324  * Returns the first item in the collection which elicits a true return value from the
12325  * passed selection function.
12326  * @param {Function} fn The selection function to execute for each item.
12327  * @param {Object} scope (optional) The scope in which to execute the function.
12328  * @return {Object} The first item in the collection which returned true from the selection function.
12329  */
12330     find : function(fn, scope){
12331         for(var i = 0, len = this.items.length; i < len; i++){
12332             if(fn.call(scope || window, this.items[i], this.keys[i])){
12333                 return this.items[i];
12334             }
12335         }
12336         return null;
12337     },
12338    
12339 /**
12340  * Inserts an item at the specified index in the collection.
12341  * @param {Number} index The index to insert the item at.
12342  * @param {String} key The key to associate with the new item, or the item itself.
12343  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12344  * @return {Object} The item inserted.
12345  */
12346     insert : function(index, key, o){
12347         if(arguments.length == 2){
12348             o = arguments[1];
12349             key = this.getKey(o);
12350         }
12351         if(index >= this.length){
12352             return this.add(key, o);
12353         }
12354         this.length++;
12355         this.items.splice(index, 0, o);
12356         if(typeof key != "undefined" && key != null){
12357             this.map[key] = o;
12358         }
12359         this.keys.splice(index, 0, key);
12360         this.fireEvent("add", index, o, key);
12361         return o;
12362     },
12363    
12364 /**
12365  * Removed an item from the collection.
12366  * @param {Object} o The item to remove.
12367  * @return {Object} The item removed.
12368  */
12369     remove : function(o){
12370         return this.removeAt(this.indexOf(o));
12371     },
12372    
12373 /**
12374  * Remove an item from a specified index in the collection.
12375  * @param {Number} index The index within the collection of the item to remove.
12376  */
12377     removeAt : function(index){
12378         if(index < this.length && index >= 0){
12379             this.length--;
12380             var o = this.items[index];
12381             this.items.splice(index, 1);
12382             var key = this.keys[index];
12383             if(typeof key != "undefined"){
12384                 delete this.map[key];
12385             }
12386             this.keys.splice(index, 1);
12387             this.fireEvent("remove", o, key);
12388         }
12389     },
12390    
12391 /**
12392  * Removed an item associated with the passed key fom the collection.
12393  * @param {String} key The key of the item to remove.
12394  */
12395     removeKey : function(key){
12396         return this.removeAt(this.indexOfKey(key));
12397     },
12398    
12399 /**
12400  * Returns the number of items in the collection.
12401  * @return {Number} the number of items in the collection.
12402  */
12403     getCount : function(){
12404         return this.length; 
12405     },
12406    
12407 /**
12408  * Returns index within the collection of the passed Object.
12409  * @param {Object} o The item to find the index of.
12410  * @return {Number} index of the item.
12411  */
12412     indexOf : function(o){
12413         if(!this.items.indexOf){
12414             for(var i = 0, len = this.items.length; i < len; i++){
12415                 if(this.items[i] == o) return i;
12416             }
12417             return -1;
12418         }else{
12419             return this.items.indexOf(o);
12420         }
12421     },
12422    
12423 /**
12424  * Returns index within the collection of the passed key.
12425  * @param {String} key The key to find the index of.
12426  * @return {Number} index of the key.
12427  */
12428     indexOfKey : function(key){
12429         if(!this.keys.indexOf){
12430             for(var i = 0, len = this.keys.length; i < len; i++){
12431                 if(this.keys[i] == key) return i;
12432             }
12433             return -1;
12434         }else{
12435             return this.keys.indexOf(key);
12436         }
12437     },
12438    
12439 /**
12440  * Returns the item associated with the passed key OR index. Key has priority over index.
12441  * @param {String/Number} key The key or index of the item.
12442  * @return {Object} The item associated with the passed key.
12443  */
12444     item : function(key){
12445         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12446         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12447     },
12448     
12449 /**
12450  * Returns the item at the specified index.
12451  * @param {Number} index The index of the item.
12452  * @return {Object}
12453  */
12454     itemAt : function(index){
12455         return this.items[index];
12456     },
12457     
12458 /**
12459  * Returns the item associated with the passed key.
12460  * @param {String/Number} key The key of the item.
12461  * @return {Object} The item associated with the passed key.
12462  */
12463     key : function(key){
12464         return this.map[key];
12465     },
12466    
12467 /**
12468  * Returns true if the collection contains the passed Object as an item.
12469  * @param {Object} o  The Object to look for in the collection.
12470  * @return {Boolean} True if the collection contains the Object as an item.
12471  */
12472     contains : function(o){
12473         return this.indexOf(o) != -1;
12474     },
12475    
12476 /**
12477  * Returns true if the collection contains the passed Object as a key.
12478  * @param {String} key The key to look for in the collection.
12479  * @return {Boolean} True if the collection contains the Object as a key.
12480  */
12481     containsKey : function(key){
12482         return typeof this.map[key] != "undefined";
12483     },
12484    
12485 /**
12486  * Removes all items from the collection.
12487  */
12488     clear : function(){
12489         this.length = 0;
12490         this.items = [];
12491         this.keys = [];
12492         this.map = {};
12493         this.fireEvent("clear");
12494     },
12495    
12496 /**
12497  * Returns the first item in the collection.
12498  * @return {Object} the first item in the collection..
12499  */
12500     first : function(){
12501         return this.items[0]; 
12502     },
12503    
12504 /**
12505  * Returns the last item in the collection.
12506  * @return {Object} the last item in the collection..
12507  */
12508     last : function(){
12509         return this.items[this.length-1];   
12510     },
12511     
12512     _sort : function(property, dir, fn){
12513         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12514         fn = fn || function(a, b){
12515             return a-b;
12516         };
12517         var c = [], k = this.keys, items = this.items;
12518         for(var i = 0, len = items.length; i < len; i++){
12519             c[c.length] = {key: k[i], value: items[i], index: i};
12520         }
12521         c.sort(function(a, b){
12522             var v = fn(a[property], b[property]) * dsc;
12523             if(v == 0){
12524                 v = (a.index < b.index ? -1 : 1);
12525             }
12526             return v;
12527         });
12528         for(var i = 0, len = c.length; i < len; i++){
12529             items[i] = c[i].value;
12530             k[i] = c[i].key;
12531         }
12532         this.fireEvent("sort", this);
12533     },
12534     
12535     /**
12536      * Sorts this collection with the passed comparison function
12537      * @param {String} direction (optional) "ASC" or "DESC"
12538      * @param {Function} fn (optional) comparison function
12539      */
12540     sort : function(dir, fn){
12541         this._sort("value", dir, fn);
12542     },
12543     
12544     /**
12545      * Sorts this collection by keys
12546      * @param {String} direction (optional) "ASC" or "DESC"
12547      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12548      */
12549     keySort : function(dir, fn){
12550         this._sort("key", dir, fn || function(a, b){
12551             return String(a).toUpperCase()-String(b).toUpperCase();
12552         });
12553     },
12554     
12555     /**
12556      * Returns a range of items in this collection
12557      * @param {Number} startIndex (optional) defaults to 0
12558      * @param {Number} endIndex (optional) default to the last item
12559      * @return {Array} An array of items
12560      */
12561     getRange : function(start, end){
12562         var items = this.items;
12563         if(items.length < 1){
12564             return [];
12565         }
12566         start = start || 0;
12567         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12568         var r = [];
12569         if(start <= end){
12570             for(var i = start; i <= end; i++) {
12571                     r[r.length] = items[i];
12572             }
12573         }else{
12574             for(var i = start; i >= end; i--) {
12575                     r[r.length] = items[i];
12576             }
12577         }
12578         return r;
12579     },
12580         
12581     /**
12582      * Filter the <i>objects</i> in this collection by a specific property. 
12583      * Returns a new collection that has been filtered.
12584      * @param {String} property A property on your objects
12585      * @param {String/RegExp} value Either string that the property values 
12586      * should start with or a RegExp to test against the property
12587      * @return {MixedCollection} The new filtered collection
12588      */
12589     filter : function(property, value){
12590         if(!value.exec){ // not a regex
12591             value = String(value);
12592             if(value.length == 0){
12593                 return this.clone();
12594             }
12595             value = new RegExp("^" + Roo.escapeRe(value), "i");
12596         }
12597         return this.filterBy(function(o){
12598             return o && value.test(o[property]);
12599         });
12600         },
12601     
12602     /**
12603      * Filter by a function. * Returns a new collection that has been filtered.
12604      * The passed function will be called with each 
12605      * object in the collection. If the function returns true, the value is included 
12606      * otherwise it is filtered.
12607      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12608      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12609      * @return {MixedCollection} The new filtered collection
12610      */
12611     filterBy : function(fn, scope){
12612         var r = new Roo.util.MixedCollection();
12613         r.getKey = this.getKey;
12614         var k = this.keys, it = this.items;
12615         for(var i = 0, len = it.length; i < len; i++){
12616             if(fn.call(scope||this, it[i], k[i])){
12617                                 r.add(k[i], it[i]);
12618                         }
12619         }
12620         return r;
12621     },
12622     
12623     /**
12624      * Creates a duplicate of this collection
12625      * @return {MixedCollection}
12626      */
12627     clone : function(){
12628         var r = new Roo.util.MixedCollection();
12629         var k = this.keys, it = this.items;
12630         for(var i = 0, len = it.length; i < len; i++){
12631             r.add(k[i], it[i]);
12632         }
12633         r.getKey = this.getKey;
12634         return r;
12635     }
12636 });
12637 /**
12638  * Returns the item associated with the passed key or index.
12639  * @method
12640  * @param {String/Number} key The key or index of the item.
12641  * @return {Object} The item associated with the passed key.
12642  */
12643 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12644  * Based on:
12645  * Ext JS Library 1.1.1
12646  * Copyright(c) 2006-2007, Ext JS, LLC.
12647  *
12648  * Originally Released Under LGPL - original licence link has changed is not relivant.
12649  *
12650  * Fork - LGPL
12651  * <script type="text/javascript">
12652  */
12653 /**
12654  * @class Roo.util.JSON
12655  * Modified version of Douglas Crockford"s json.js that doesn"t
12656  * mess with the Object prototype 
12657  * http://www.json.org/js.html
12658  * @singleton
12659  */
12660 Roo.util.JSON = new (function(){
12661     var useHasOwn = {}.hasOwnProperty ? true : false;
12662     
12663     // crashes Safari in some instances
12664     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12665     
12666     var pad = function(n) {
12667         return n < 10 ? "0" + n : n;
12668     };
12669     
12670     var m = {
12671         "\b": '\\b',
12672         "\t": '\\t',
12673         "\n": '\\n',
12674         "\f": '\\f',
12675         "\r": '\\r',
12676         '"' : '\\"',
12677         "\\": '\\\\'
12678     };
12679
12680     var encodeString = function(s){
12681         if (/["\\\x00-\x1f]/.test(s)) {
12682             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12683                 var c = m[b];
12684                 if(c){
12685                     return c;
12686                 }
12687                 c = b.charCodeAt();
12688                 return "\\u00" +
12689                     Math.floor(c / 16).toString(16) +
12690                     (c % 16).toString(16);
12691             }) + '"';
12692         }
12693         return '"' + s + '"';
12694     };
12695     
12696     var encodeArray = function(o){
12697         var a = ["["], b, i, l = o.length, v;
12698             for (i = 0; i < l; i += 1) {
12699                 v = o[i];
12700                 switch (typeof v) {
12701                     case "undefined":
12702                     case "function":
12703                     case "unknown":
12704                         break;
12705                     default:
12706                         if (b) {
12707                             a.push(',');
12708                         }
12709                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12710                         b = true;
12711                 }
12712             }
12713             a.push("]");
12714             return a.join("");
12715     };
12716     
12717     var encodeDate = function(o){
12718         return '"' + o.getFullYear() + "-" +
12719                 pad(o.getMonth() + 1) + "-" +
12720                 pad(o.getDate()) + "T" +
12721                 pad(o.getHours()) + ":" +
12722                 pad(o.getMinutes()) + ":" +
12723                 pad(o.getSeconds()) + '"';
12724     };
12725     
12726     /**
12727      * Encodes an Object, Array or other value
12728      * @param {Mixed} o The variable to encode
12729      * @return {String} The JSON string
12730      */
12731     this.encode = function(o){
12732         if(typeof o == "undefined" || o === null){
12733             return "null";
12734         }else if(o instanceof Array){
12735             return encodeArray(o);
12736         }else if(o instanceof Date){
12737             return encodeDate(o);
12738         }else if(typeof o == "string"){
12739             return encodeString(o);
12740         }else if(typeof o == "number"){
12741             return isFinite(o) ? String(o) : "null";
12742         }else if(typeof o == "boolean"){
12743             return String(o);
12744         }else {
12745             var a = ["{"], b, i, v;
12746             for (i in o) {
12747                 if(!useHasOwn || o.hasOwnProperty(i)) {
12748                     v = o[i];
12749                     switch (typeof v) {
12750                     case "undefined":
12751                     case "function":
12752                     case "unknown":
12753                         break;
12754                     default:
12755                         if(b){
12756                             a.push(',');
12757                         }
12758                         a.push(this.encode(i), ":",
12759                                 v === null ? "null" : this.encode(v));
12760                         b = true;
12761                     }
12762                 }
12763             }
12764             a.push("}");
12765             return a.join("");
12766         }
12767     };
12768     
12769     /**
12770      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12771      * @param {String} json The JSON string
12772      * @return {Object} The resulting object
12773      */
12774     this.decode = function(json){
12775         /**
12776          * eval:var:json
12777          */
12778         return eval("(" + json + ')');
12779     };
12780 })();
12781 /** 
12782  * Shorthand for {@link Roo.util.JSON#encode}
12783  * @member Roo encode 
12784  * @method */
12785 Roo.encode = Roo.util.JSON.encode;
12786 /** 
12787  * Shorthand for {@link Roo.util.JSON#decode}
12788  * @member Roo decode 
12789  * @method */
12790 Roo.decode = Roo.util.JSON.decode;
12791 /*
12792  * Based on:
12793  * Ext JS Library 1.1.1
12794  * Copyright(c) 2006-2007, Ext JS, LLC.
12795  *
12796  * Originally Released Under LGPL - original licence link has changed is not relivant.
12797  *
12798  * Fork - LGPL
12799  * <script type="text/javascript">
12800  */
12801  
12802 /**
12803  * @class Roo.util.Format
12804  * Reusable data formatting functions
12805  * @singleton
12806  */
12807 Roo.util.Format = function(){
12808     var trimRe = /^\s+|\s+$/g;
12809     return {
12810         /**
12811          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12812          * @param {String} value The string to truncate
12813          * @param {Number} length The maximum length to allow before truncating
12814          * @return {String} The converted text
12815          */
12816         ellipsis : function(value, len){
12817             if(value && value.length > len){
12818                 return value.substr(0, len-3)+"...";
12819             }
12820             return value;
12821         },
12822
12823         /**
12824          * Checks a reference and converts it to empty string if it is undefined
12825          * @param {Mixed} value Reference to check
12826          * @return {Mixed} Empty string if converted, otherwise the original value
12827          */
12828         undef : function(value){
12829             return typeof value != "undefined" ? value : "";
12830         },
12831
12832         /**
12833          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12834          * @param {String} value The string to encode
12835          * @return {String} The encoded text
12836          */
12837         htmlEncode : function(value){
12838             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12839         },
12840
12841         /**
12842          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12843          * @param {String} value The string to decode
12844          * @return {String} The decoded text
12845          */
12846         htmlDecode : function(value){
12847             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12848         },
12849
12850         /**
12851          * Trims any whitespace from either side of a string
12852          * @param {String} value The text to trim
12853          * @return {String} The trimmed text
12854          */
12855         trim : function(value){
12856             return String(value).replace(trimRe, "");
12857         },
12858
12859         /**
12860          * Returns a substring from within an original string
12861          * @param {String} value The original text
12862          * @param {Number} start The start index of the substring
12863          * @param {Number} length The length of the substring
12864          * @return {String} The substring
12865          */
12866         substr : function(value, start, length){
12867             return String(value).substr(start, length);
12868         },
12869
12870         /**
12871          * Converts a string to all lower case letters
12872          * @param {String} value The text to convert
12873          * @return {String} The converted text
12874          */
12875         lowercase : function(value){
12876             return String(value).toLowerCase();
12877         },
12878
12879         /**
12880          * Converts a string to all upper case letters
12881          * @param {String} value The text to convert
12882          * @return {String} The converted text
12883          */
12884         uppercase : function(value){
12885             return String(value).toUpperCase();
12886         },
12887
12888         /**
12889          * Converts the first character only of a string to upper case
12890          * @param {String} value The text to convert
12891          * @return {String} The converted text
12892          */
12893         capitalize : function(value){
12894             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12895         },
12896
12897         // private
12898         call : function(value, fn){
12899             if(arguments.length > 2){
12900                 var args = Array.prototype.slice.call(arguments, 2);
12901                 args.unshift(value);
12902                  
12903                 return /** eval:var:value */  eval(fn).apply(window, args);
12904             }else{
12905                 /** eval:var:value */
12906                 return /** eval:var:value */ eval(fn).call(window, value);
12907             }
12908         },
12909
12910         /**
12911          * Format a number as US currency
12912          * @param {Number/String} value The numeric value to format
12913          * @return {String} The formatted currency string
12914          */
12915         usMoney : function(v){
12916             v = (Math.round((v-0)*100))/100;
12917             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12918             v = String(v);
12919             var ps = v.split('.');
12920             var whole = ps[0];
12921             var sub = ps[1] ? '.'+ ps[1] : '.00';
12922             var r = /(\d+)(\d{3})/;
12923             while (r.test(whole)) {
12924                 whole = whole.replace(r, '$1' + ',' + '$2');
12925             }
12926             return "$" + whole + sub ;
12927         },
12928
12929         /**
12930          * Parse a value into a formatted date using the specified format pattern.
12931          * @param {Mixed} value The value to format
12932          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12933          * @return {String} The formatted date string
12934          */
12935         date : function(v, format){
12936             if(!v){
12937                 return "";
12938             }
12939             if(!(v instanceof Date)){
12940                 v = new Date(Date.parse(v));
12941             }
12942             return v.dateFormat(format || "m/d/Y");
12943         },
12944
12945         /**
12946          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12947          * @param {String} format Any valid date format string
12948          * @return {Function} The date formatting function
12949          */
12950         dateRenderer : function(format){
12951             return function(v){
12952                 return Roo.util.Format.date(v, format);  
12953             };
12954         },
12955
12956         // private
12957         stripTagsRE : /<\/?[^>]+>/gi,
12958         
12959         /**
12960          * Strips all HTML tags
12961          * @param {Mixed} value The text from which to strip tags
12962          * @return {String} The stripped text
12963          */
12964         stripTags : function(v){
12965             return !v ? v : String(v).replace(this.stripTagsRE, "");
12966         }
12967     };
12968 }();/*
12969  * Based on:
12970  * Ext JS Library 1.1.1
12971  * Copyright(c) 2006-2007, Ext JS, LLC.
12972  *
12973  * Originally Released Under LGPL - original licence link has changed is not relivant.
12974  *
12975  * Fork - LGPL
12976  * <script type="text/javascript">
12977  */
12978
12979
12980  
12981
12982 /**
12983  * @class Roo.MasterTemplate
12984  * @extends Roo.Template
12985  * Provides a template that can have child templates. The syntax is:
12986 <pre><code>
12987 var t = new Roo.MasterTemplate(
12988         '&lt;select name="{name}"&gt;',
12989                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
12990         '&lt;/select&gt;'
12991 );
12992 t.add('options', {value: 'foo', text: 'bar'});
12993 // or you can add multiple child elements in one shot
12994 t.addAll('options', [
12995     {value: 'foo', text: 'bar'},
12996     {value: 'foo2', text: 'bar2'},
12997     {value: 'foo3', text: 'bar3'}
12998 ]);
12999 // then append, applying the master template values
13000 t.append('my-form', {name: 'my-select'});
13001 </code></pre>
13002 * A name attribute for the child template is not required if you have only one child
13003 * template or you want to refer to them by index.
13004  */
13005 Roo.MasterTemplate = function(){
13006     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13007     this.originalHtml = this.html;
13008     var st = {};
13009     var m, re = this.subTemplateRe;
13010     re.lastIndex = 0;
13011     var subIndex = 0;
13012     while(m = re.exec(this.html)){
13013         var name = m[1], content = m[2];
13014         st[subIndex] = {
13015             name: name,
13016             index: subIndex,
13017             buffer: [],
13018             tpl : new Roo.Template(content)
13019         };
13020         if(name){
13021             st[name] = st[subIndex];
13022         }
13023         st[subIndex].tpl.compile();
13024         st[subIndex].tpl.call = this.call.createDelegate(this);
13025         subIndex++;
13026     }
13027     this.subCount = subIndex;
13028     this.subs = st;
13029 };
13030 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13031     /**
13032     * The regular expression used to match sub templates
13033     * @type RegExp
13034     * @property
13035     */
13036     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13037
13038     /**
13039      * Applies the passed values to a child template.
13040      * @param {String/Number} name (optional) The name or index of the child template
13041      * @param {Array/Object} values The values to be applied to the template
13042      * @return {MasterTemplate} this
13043      */
13044      add : function(name, values){
13045         if(arguments.length == 1){
13046             values = arguments[0];
13047             name = 0;
13048         }
13049         var s = this.subs[name];
13050         s.buffer[s.buffer.length] = s.tpl.apply(values);
13051         return this;
13052     },
13053
13054     /**
13055      * Applies all the passed values to a child template.
13056      * @param {String/Number} name (optional) The name or index of the child template
13057      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13058      * @param {Boolean} reset (optional) True to reset the template first
13059      * @return {MasterTemplate} this
13060      */
13061     fill : function(name, values, reset){
13062         var a = arguments;
13063         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13064             values = a[0];
13065             name = 0;
13066             reset = a[1];
13067         }
13068         if(reset){
13069             this.reset();
13070         }
13071         for(var i = 0, len = values.length; i < len; i++){
13072             this.add(name, values[i]);
13073         }
13074         return this;
13075     },
13076
13077     /**
13078      * Resets the template for reuse
13079      * @return {MasterTemplate} this
13080      */
13081      reset : function(){
13082         var s = this.subs;
13083         for(var i = 0; i < this.subCount; i++){
13084             s[i].buffer = [];
13085         }
13086         return this;
13087     },
13088
13089     applyTemplate : function(values){
13090         var s = this.subs;
13091         var replaceIndex = -1;
13092         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13093             return s[++replaceIndex].buffer.join("");
13094         });
13095         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13096     },
13097
13098     apply : function(){
13099         return this.applyTemplate.apply(this, arguments);
13100     },
13101
13102     compile : function(){return this;}
13103 });
13104
13105 /**
13106  * Alias for fill().
13107  * @method
13108  */
13109 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13110  /**
13111  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13112  * var tpl = Roo.MasterTemplate.from('element-id');
13113  * @param {String/HTMLElement} el
13114  * @param {Object} config
13115  * @static
13116  */
13117 Roo.MasterTemplate.from = function(el, config){
13118     el = Roo.getDom(el);
13119     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13120 };/*
13121  * Based on:
13122  * Ext JS Library 1.1.1
13123  * Copyright(c) 2006-2007, Ext JS, LLC.
13124  *
13125  * Originally Released Under LGPL - original licence link has changed is not relivant.
13126  *
13127  * Fork - LGPL
13128  * <script type="text/javascript">
13129  */
13130
13131  
13132 /**
13133  * @class Roo.util.CSS
13134  * Utility class for manipulating CSS rules
13135  * @singleton
13136  */
13137 Roo.util.CSS = function(){
13138         var rules = null;
13139         var doc = document;
13140
13141     var camelRe = /(-[a-z])/gi;
13142     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13143
13144    return {
13145    /**
13146     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13147     * tag and appended to the HEAD of the document.
13148     * @param {String} cssText The text containing the css rules
13149     * @param {String} id An id to add to the stylesheet for later removal
13150     * @return {StyleSheet}
13151     */
13152    createStyleSheet : function(cssText, id){
13153        var ss;
13154        var head = doc.getElementsByTagName("head")[0];
13155        var rules = doc.createElement("style");
13156        rules.setAttribute("type", "text/css");
13157        if(id){
13158            rules.setAttribute("id", id);
13159        }
13160        if(Roo.isIE){
13161            head.appendChild(rules);
13162            ss = rules.styleSheet;
13163            ss.cssText = cssText;
13164        }else{
13165            try{
13166                 rules.appendChild(doc.createTextNode(cssText));
13167            }catch(e){
13168                rules.cssText = cssText; 
13169            }
13170            head.appendChild(rules);
13171            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13172        }
13173        this.cacheStyleSheet(ss);
13174        return ss;
13175    },
13176
13177    /**
13178     * Removes a style or link tag by id
13179     * @param {String} id The id of the tag
13180     */
13181    removeStyleSheet : function(id){
13182        var existing = doc.getElementById(id);
13183        if(existing){
13184            existing.parentNode.removeChild(existing);
13185        }
13186    },
13187
13188    /**
13189     * Dynamically swaps an existing stylesheet reference for a new one
13190     * @param {String} id The id of an existing link tag to remove
13191     * @param {String} url The href of the new stylesheet to include
13192     */
13193    swapStyleSheet : function(id, url){
13194        this.removeStyleSheet(id);
13195        var ss = doc.createElement("link");
13196        ss.setAttribute("rel", "stylesheet");
13197        ss.setAttribute("type", "text/css");
13198        ss.setAttribute("id", id);
13199        ss.setAttribute("href", url);
13200        doc.getElementsByTagName("head")[0].appendChild(ss);
13201    },
13202    
13203    /**
13204     * Refresh the rule cache if you have dynamically added stylesheets
13205     * @return {Object} An object (hash) of rules indexed by selector
13206     */
13207    refreshCache : function(){
13208        return this.getRules(true);
13209    },
13210
13211    // private
13212    cacheStyleSheet : function(ss){
13213        if(!rules){
13214            rules = {};
13215        }
13216        try{// try catch for cross domain access issue
13217            var ssRules = ss.cssRules || ss.rules;
13218            for(var j = ssRules.length-1; j >= 0; --j){
13219                rules[ssRules[j].selectorText] = ssRules[j];
13220            }
13221        }catch(e){}
13222    },
13223    
13224    /**
13225     * Gets all css rules for the document
13226     * @param {Boolean} refreshCache true to refresh the internal cache
13227     * @return {Object} An object (hash) of rules indexed by selector
13228     */
13229    getRules : function(refreshCache){
13230                 if(rules == null || refreshCache){
13231                         rules = {};
13232                         var ds = doc.styleSheets;
13233                         for(var i =0, len = ds.length; i < len; i++){
13234                             try{
13235                         this.cacheStyleSheet(ds[i]);
13236                     }catch(e){} 
13237                 }
13238                 }
13239                 return rules;
13240         },
13241         
13242         /**
13243     * Gets an an individual CSS rule by selector(s)
13244     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13245     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13246     * @return {CSSRule} The CSS rule or null if one is not found
13247     */
13248    getRule : function(selector, refreshCache){
13249                 var rs = this.getRules(refreshCache);
13250                 if(!(selector instanceof Array)){
13251                     return rs[selector];
13252                 }
13253                 for(var i = 0; i < selector.length; i++){
13254                         if(rs[selector[i]]){
13255                                 return rs[selector[i]];
13256                         }
13257                 }
13258                 return null;
13259         },
13260         
13261         
13262         /**
13263     * Updates a rule property
13264     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13265     * @param {String} property The css property
13266     * @param {String} value The new value for the property
13267     * @return {Boolean} true If a rule was found and updated
13268     */
13269    updateRule : function(selector, property, value){
13270                 if(!(selector instanceof Array)){
13271                         var rule = this.getRule(selector);
13272                         if(rule){
13273                                 rule.style[property.replace(camelRe, camelFn)] = value;
13274                                 return true;
13275                         }
13276                 }else{
13277                         for(var i = 0; i < selector.length; i++){
13278                                 if(this.updateRule(selector[i], property, value)){
13279                                         return true;
13280                                 }
13281                         }
13282                 }
13283                 return false;
13284         }
13285    };   
13286 }();/*
13287  * Based on:
13288  * Ext JS Library 1.1.1
13289  * Copyright(c) 2006-2007, Ext JS, LLC.
13290  *
13291  * Originally Released Under LGPL - original licence link has changed is not relivant.
13292  *
13293  * Fork - LGPL
13294  * <script type="text/javascript">
13295  */
13296
13297  
13298
13299 /**
13300  * @class Roo.util.ClickRepeater
13301  * @extends Roo.util.Observable
13302  * 
13303  * A wrapper class which can be applied to any element. Fires a "click" event while the
13304  * mouse is pressed. The interval between firings may be specified in the config but
13305  * defaults to 10 milliseconds.
13306  * 
13307  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13308  * 
13309  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13310  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13311  * Similar to an autorepeat key delay.
13312  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13313  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13314  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13315  *           "interval" and "delay" are ignored. "immediate" is honored.
13316  * @cfg {Boolean} preventDefault True to prevent the default click event
13317  * @cfg {Boolean} stopDefault True to stop the default click event
13318  * 
13319  * @history
13320  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13321  *     2007-02-02 jvs Renamed to ClickRepeater
13322  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13323  *
13324  *  @constructor
13325  * @param {String/HTMLElement/Element} el The element to listen on
13326  * @param {Object} config
13327  **/
13328 Roo.util.ClickRepeater = function(el, config)
13329 {
13330     this.el = Roo.get(el);
13331     this.el.unselectable();
13332
13333     Roo.apply(this, config);
13334
13335     this.addEvents({
13336     /**
13337      * @event mousedown
13338      * Fires when the mouse button is depressed.
13339      * @param {Roo.util.ClickRepeater} this
13340      */
13341         "mousedown" : true,
13342     /**
13343      * @event click
13344      * Fires on a specified interval during the time the element is pressed.
13345      * @param {Roo.util.ClickRepeater} this
13346      */
13347         "click" : true,
13348     /**
13349      * @event mouseup
13350      * Fires when the mouse key is released.
13351      * @param {Roo.util.ClickRepeater} this
13352      */
13353         "mouseup" : true
13354     });
13355
13356     this.el.on("mousedown", this.handleMouseDown, this);
13357     if(this.preventDefault || this.stopDefault){
13358         this.el.on("click", function(e){
13359             if(this.preventDefault){
13360                 e.preventDefault();
13361             }
13362             if(this.stopDefault){
13363                 e.stopEvent();
13364             }
13365         }, this);
13366     }
13367
13368     // allow inline handler
13369     if(this.handler){
13370         this.on("click", this.handler,  this.scope || this);
13371     }
13372
13373     Roo.util.ClickRepeater.superclass.constructor.call(this);
13374 };
13375
13376 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13377     interval : 20,
13378     delay: 250,
13379     preventDefault : true,
13380     stopDefault : false,
13381     timer : 0,
13382
13383     // private
13384     handleMouseDown : function(){
13385         clearTimeout(this.timer);
13386         this.el.blur();
13387         if(this.pressClass){
13388             this.el.addClass(this.pressClass);
13389         }
13390         this.mousedownTime = new Date();
13391
13392         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13393         this.el.on("mouseout", this.handleMouseOut, this);
13394
13395         this.fireEvent("mousedown", this);
13396         this.fireEvent("click", this);
13397         
13398         this.timer = this.click.defer(this.delay || this.interval, this);
13399     },
13400
13401     // private
13402     click : function(){
13403         this.fireEvent("click", this);
13404         this.timer = this.click.defer(this.getInterval(), this);
13405     },
13406
13407     // private
13408     getInterval: function(){
13409         if(!this.accelerate){
13410             return this.interval;
13411         }
13412         var pressTime = this.mousedownTime.getElapsed();
13413         if(pressTime < 500){
13414             return 400;
13415         }else if(pressTime < 1700){
13416             return 320;
13417         }else if(pressTime < 2600){
13418             return 250;
13419         }else if(pressTime < 3500){
13420             return 180;
13421         }else if(pressTime < 4400){
13422             return 140;
13423         }else if(pressTime < 5300){
13424             return 80;
13425         }else if(pressTime < 6200){
13426             return 50;
13427         }else{
13428             return 10;
13429         }
13430     },
13431
13432     // private
13433     handleMouseOut : function(){
13434         clearTimeout(this.timer);
13435         if(this.pressClass){
13436             this.el.removeClass(this.pressClass);
13437         }
13438         this.el.on("mouseover", this.handleMouseReturn, this);
13439     },
13440
13441     // private
13442     handleMouseReturn : function(){
13443         this.el.un("mouseover", this.handleMouseReturn);
13444         if(this.pressClass){
13445             this.el.addClass(this.pressClass);
13446         }
13447         this.click();
13448     },
13449
13450     // private
13451     handleMouseUp : function(){
13452         clearTimeout(this.timer);
13453         this.el.un("mouseover", this.handleMouseReturn);
13454         this.el.un("mouseout", this.handleMouseOut);
13455         Roo.get(document).un("mouseup", this.handleMouseUp);
13456         this.el.removeClass(this.pressClass);
13457         this.fireEvent("mouseup", this);
13458     }
13459 });/*
13460  * Based on:
13461  * Ext JS Library 1.1.1
13462  * Copyright(c) 2006-2007, Ext JS, LLC.
13463  *
13464  * Originally Released Under LGPL - original licence link has changed is not relivant.
13465  *
13466  * Fork - LGPL
13467  * <script type="text/javascript">
13468  */
13469
13470  
13471 /**
13472  * @class Roo.KeyNav
13473  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13474  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13475  * way to implement custom navigation schemes for any UI component.</p>
13476  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13477  * pageUp, pageDown, del, home, end.  Usage:</p>
13478  <pre><code>
13479 var nav = new Roo.KeyNav("my-element", {
13480     "left" : function(e){
13481         this.moveLeft(e.ctrlKey);
13482     },
13483     "right" : function(e){
13484         this.moveRight(e.ctrlKey);
13485     },
13486     "enter" : function(e){
13487         this.save();
13488     },
13489     scope : this
13490 });
13491 </code></pre>
13492  * @constructor
13493  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13494  * @param {Object} config The config
13495  */
13496 Roo.KeyNav = function(el, config){
13497     this.el = Roo.get(el);
13498     Roo.apply(this, config);
13499     if(!this.disabled){
13500         this.disabled = true;
13501         this.enable();
13502     }
13503 };
13504
13505 Roo.KeyNav.prototype = {
13506     /**
13507      * @cfg {Boolean} disabled
13508      * True to disable this KeyNav instance (defaults to false)
13509      */
13510     disabled : false,
13511     /**
13512      * @cfg {String} defaultEventAction
13513      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13514      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13515      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13516      */
13517     defaultEventAction: "stopEvent",
13518     /**
13519      * @cfg {Boolean} forceKeyDown
13520      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13521      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13522      * handle keydown instead of keypress.
13523      */
13524     forceKeyDown : false,
13525
13526     // private
13527     prepareEvent : function(e){
13528         var k = e.getKey();
13529         var h = this.keyToHandler[k];
13530         //if(h && this[h]){
13531         //    e.stopPropagation();
13532         //}
13533         if(Roo.isSafari && h && k >= 37 && k <= 40){
13534             e.stopEvent();
13535         }
13536     },
13537
13538     // private
13539     relay : function(e){
13540         var k = e.getKey();
13541         var h = this.keyToHandler[k];
13542         if(h && this[h]){
13543             if(this.doRelay(e, this[h], h) !== true){
13544                 e[this.defaultEventAction]();
13545             }
13546         }
13547     },
13548
13549     // private
13550     doRelay : function(e, h, hname){
13551         return h.call(this.scope || this, e);
13552     },
13553
13554     // possible handlers
13555     enter : false,
13556     left : false,
13557     right : false,
13558     up : false,
13559     down : false,
13560     tab : false,
13561     esc : false,
13562     pageUp : false,
13563     pageDown : false,
13564     del : false,
13565     home : false,
13566     end : false,
13567
13568     // quick lookup hash
13569     keyToHandler : {
13570         37 : "left",
13571         39 : "right",
13572         38 : "up",
13573         40 : "down",
13574         33 : "pageUp",
13575         34 : "pageDown",
13576         46 : "del",
13577         36 : "home",
13578         35 : "end",
13579         13 : "enter",
13580         27 : "esc",
13581         9  : "tab"
13582     },
13583
13584         /**
13585          * Enable this KeyNav
13586          */
13587         enable: function(){
13588                 if(this.disabled){
13589             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13590             // the EventObject will normalize Safari automatically
13591             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13592                 this.el.on("keydown", this.relay,  this);
13593             }else{
13594                 this.el.on("keydown", this.prepareEvent,  this);
13595                 this.el.on("keypress", this.relay,  this);
13596             }
13597                     this.disabled = false;
13598                 }
13599         },
13600
13601         /**
13602          * Disable this KeyNav
13603          */
13604         disable: function(){
13605                 if(!this.disabled){
13606                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13607                 this.el.un("keydown", this.relay);
13608             }else{
13609                 this.el.un("keydown", this.prepareEvent);
13610                 this.el.un("keypress", this.relay);
13611             }
13612                     this.disabled = true;
13613                 }
13614         }
13615 };/*
13616  * Based on:
13617  * Ext JS Library 1.1.1
13618  * Copyright(c) 2006-2007, Ext JS, LLC.
13619  *
13620  * Originally Released Under LGPL - original licence link has changed is not relivant.
13621  *
13622  * Fork - LGPL
13623  * <script type="text/javascript">
13624  */
13625
13626  
13627 /**
13628  * @class Roo.KeyMap
13629  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13630  * The constructor accepts the same config object as defined by {@link #addBinding}.
13631  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13632  * combination it will call the function with this signature (if the match is a multi-key
13633  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13634  * A KeyMap can also handle a string representation of keys.<br />
13635  * Usage:
13636  <pre><code>
13637 // map one key by key code
13638 var map = new Roo.KeyMap("my-element", {
13639     key: 13, // or Roo.EventObject.ENTER
13640     fn: myHandler,
13641     scope: myObject
13642 });
13643
13644 // map multiple keys to one action by string
13645 var map = new Roo.KeyMap("my-element", {
13646     key: "a\r\n\t",
13647     fn: myHandler,
13648     scope: myObject
13649 });
13650
13651 // map multiple keys to multiple actions by strings and array of codes
13652 var map = new Roo.KeyMap("my-element", [
13653     {
13654         key: [10,13],
13655         fn: function(){ alert("Return was pressed"); }
13656     }, {
13657         key: "abc",
13658         fn: function(){ alert('a, b or c was pressed'); }
13659     }, {
13660         key: "\t",
13661         ctrl:true,
13662         shift:true,
13663         fn: function(){ alert('Control + shift + tab was pressed.'); }
13664     }
13665 ]);
13666 </code></pre>
13667  * <b>Note: A KeyMap starts enabled</b>
13668  * @constructor
13669  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13670  * @param {Object} config The config (see {@link #addBinding})
13671  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13672  */
13673 Roo.KeyMap = function(el, config, eventName){
13674     this.el  = Roo.get(el);
13675     this.eventName = eventName || "keydown";
13676     this.bindings = [];
13677     if(config){
13678         this.addBinding(config);
13679     }
13680     this.enable();
13681 };
13682
13683 Roo.KeyMap.prototype = {
13684     /**
13685      * True to stop the event from bubbling and prevent the default browser action if the
13686      * key was handled by the KeyMap (defaults to false)
13687      * @type Boolean
13688      */
13689     stopEvent : false,
13690
13691     /**
13692      * Add a new binding to this KeyMap. The following config object properties are supported:
13693      * <pre>
13694 Property    Type             Description
13695 ----------  ---------------  ----------------------------------------------------------------------
13696 key         String/Array     A single keycode or an array of keycodes to handle
13697 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13698 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13699 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13700 fn          Function         The function to call when KeyMap finds the expected key combination
13701 scope       Object           The scope of the callback function
13702 </pre>
13703      *
13704      * Usage:
13705      * <pre><code>
13706 // Create a KeyMap
13707 var map = new Roo.KeyMap(document, {
13708     key: Roo.EventObject.ENTER,
13709     fn: handleKey,
13710     scope: this
13711 });
13712
13713 //Add a new binding to the existing KeyMap later
13714 map.addBinding({
13715     key: 'abc',
13716     shift: true,
13717     fn: handleKey,
13718     scope: this
13719 });
13720 </code></pre>
13721      * @param {Object/Array} config A single KeyMap config or an array of configs
13722      */
13723         addBinding : function(config){
13724         if(config instanceof Array){
13725             for(var i = 0, len = config.length; i < len; i++){
13726                 this.addBinding(config[i]);
13727             }
13728             return;
13729         }
13730         var keyCode = config.key,
13731             shift = config.shift, 
13732             ctrl = config.ctrl, 
13733             alt = config.alt,
13734             fn = config.fn,
13735             scope = config.scope;
13736         if(typeof keyCode == "string"){
13737             var ks = [];
13738             var keyString = keyCode.toUpperCase();
13739             for(var j = 0, len = keyString.length; j < len; j++){
13740                 ks.push(keyString.charCodeAt(j));
13741             }
13742             keyCode = ks;
13743         }
13744         var keyArray = keyCode instanceof Array;
13745         var handler = function(e){
13746             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13747                 var k = e.getKey();
13748                 if(keyArray){
13749                     for(var i = 0, len = keyCode.length; i < len; i++){
13750                         if(keyCode[i] == k){
13751                           if(this.stopEvent){
13752                               e.stopEvent();
13753                           }
13754                           fn.call(scope || window, k, e);
13755                           return;
13756                         }
13757                     }
13758                 }else{
13759                     if(k == keyCode){
13760                         if(this.stopEvent){
13761                            e.stopEvent();
13762                         }
13763                         fn.call(scope || window, k, e);
13764                     }
13765                 }
13766             }
13767         };
13768         this.bindings.push(handler);  
13769         },
13770
13771     /**
13772      * Shorthand for adding a single key listener
13773      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13774      * following options:
13775      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13776      * @param {Function} fn The function to call
13777      * @param {Object} scope (optional) The scope of the function
13778      */
13779     on : function(key, fn, scope){
13780         var keyCode, shift, ctrl, alt;
13781         if(typeof key == "object" && !(key instanceof Array)){
13782             keyCode = key.key;
13783             shift = key.shift;
13784             ctrl = key.ctrl;
13785             alt = key.alt;
13786         }else{
13787             keyCode = key;
13788         }
13789         this.addBinding({
13790             key: keyCode,
13791             shift: shift,
13792             ctrl: ctrl,
13793             alt: alt,
13794             fn: fn,
13795             scope: scope
13796         })
13797     },
13798
13799     // private
13800     handleKeyDown : function(e){
13801             if(this.enabled){ //just in case
13802             var b = this.bindings;
13803             for(var i = 0, len = b.length; i < len; i++){
13804                 b[i].call(this, e);
13805             }
13806             }
13807         },
13808         
13809         /**
13810          * Returns true if this KeyMap is enabled
13811          * @return {Boolean} 
13812          */
13813         isEnabled : function(){
13814             return this.enabled;  
13815         },
13816         
13817         /**
13818          * Enables this KeyMap
13819          */
13820         enable: function(){
13821                 if(!this.enabled){
13822                     this.el.on(this.eventName, this.handleKeyDown, this);
13823                     this.enabled = true;
13824                 }
13825         },
13826
13827         /**
13828          * Disable this KeyMap
13829          */
13830         disable: function(){
13831                 if(this.enabled){
13832                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
13833                     this.enabled = false;
13834                 }
13835         }
13836 };/*
13837  * Based on:
13838  * Ext JS Library 1.1.1
13839  * Copyright(c) 2006-2007, Ext JS, LLC.
13840  *
13841  * Originally Released Under LGPL - original licence link has changed is not relivant.
13842  *
13843  * Fork - LGPL
13844  * <script type="text/javascript">
13845  */
13846
13847  
13848 /**
13849  * @class Roo.util.TextMetrics
13850  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13851  * wide, in pixels, a given block of text will be.
13852  * @singleton
13853  */
13854 Roo.util.TextMetrics = function(){
13855     var shared;
13856     return {
13857         /**
13858          * Measures the size of the specified text
13859          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13860          * that can affect the size of the rendered text
13861          * @param {String} text The text to measure
13862          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13863          * in order to accurately measure the text height
13864          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13865          */
13866         measure : function(el, text, fixedWidth){
13867             if(!shared){
13868                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13869             }
13870             shared.bind(el);
13871             shared.setFixedWidth(fixedWidth || 'auto');
13872             return shared.getSize(text);
13873         },
13874
13875         /**
13876          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
13877          * the overhead of multiple calls to initialize the style properties on each measurement.
13878          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13879          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13880          * in order to accurately measure the text height
13881          * @return {Roo.util.TextMetrics.Instance} instance The new instance
13882          */
13883         createInstance : function(el, fixedWidth){
13884             return Roo.util.TextMetrics.Instance(el, fixedWidth);
13885         }
13886     };
13887 }();
13888
13889  
13890
13891 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13892     var ml = new Roo.Element(document.createElement('div'));
13893     document.body.appendChild(ml.dom);
13894     ml.position('absolute');
13895     ml.setLeftTop(-1000, -1000);
13896     ml.hide();
13897
13898     if(fixedWidth){
13899         ml.setWidth(fixedWidth);
13900     }
13901      
13902     var instance = {
13903         /**
13904          * Returns the size of the specified text based on the internal element's style and width properties
13905          * @memberOf Roo.util.TextMetrics.Instance#
13906          * @param {String} text The text to measure
13907          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13908          */
13909         getSize : function(text){
13910             ml.update(text);
13911             var s = ml.getSize();
13912             ml.update('');
13913             return s;
13914         },
13915
13916         /**
13917          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13918          * that can affect the size of the rendered text
13919          * @memberOf Roo.util.TextMetrics.Instance#
13920          * @param {String/HTMLElement} el The element, dom node or id
13921          */
13922         bind : function(el){
13923             ml.setStyle(
13924                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13925             );
13926         },
13927
13928         /**
13929          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
13930          * to set a fixed width in order to accurately measure the text height.
13931          * @memberOf Roo.util.TextMetrics.Instance#
13932          * @param {Number} width The width to set on the element
13933          */
13934         setFixedWidth : function(width){
13935             ml.setWidth(width);
13936         },
13937
13938         /**
13939          * Returns the measured width of the specified text
13940          * @memberOf Roo.util.TextMetrics.Instance#
13941          * @param {String} text The text to measure
13942          * @return {Number} width The width in pixels
13943          */
13944         getWidth : function(text){
13945             ml.dom.style.width = 'auto';
13946             return this.getSize(text).width;
13947         },
13948
13949         /**
13950          * Returns the measured height of the specified text.  For multiline text, be sure to call
13951          * {@link #setFixedWidth} if necessary.
13952          * @memberOf Roo.util.TextMetrics.Instance#
13953          * @param {String} text The text to measure
13954          * @return {Number} height The height in pixels
13955          */
13956         getHeight : function(text){
13957             return this.getSize(text).height;
13958         }
13959     };
13960
13961     instance.bind(bindTo);
13962
13963     return instance;
13964 };
13965
13966 // backwards compat
13967 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13968  * Based on:
13969  * Ext JS Library 1.1.1
13970  * Copyright(c) 2006-2007, Ext JS, LLC.
13971  *
13972  * Originally Released Under LGPL - original licence link has changed is not relivant.
13973  *
13974  * Fork - LGPL
13975  * <script type="text/javascript">
13976  */
13977
13978 /**
13979  * @class Roo.state.Provider
13980  * Abstract base class for state provider implementations. This class provides methods
13981  * for encoding and decoding <b>typed</b> variables including dates and defines the 
13982  * Provider interface.
13983  */
13984 Roo.state.Provider = function(){
13985     /**
13986      * @event statechange
13987      * Fires when a state change occurs.
13988      * @param {Provider} this This state provider
13989      * @param {String} key The state key which was changed
13990      * @param {String} value The encoded value for the state
13991      */
13992     this.addEvents({
13993         "statechange": true
13994     });
13995     this.state = {};
13996     Roo.state.Provider.superclass.constructor.call(this);
13997 };
13998 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13999     /**
14000      * Returns the current value for a key
14001      * @param {String} name The key name
14002      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14003      * @return {Mixed} The state data
14004      */
14005     get : function(name, defaultValue){
14006         return typeof this.state[name] == "undefined" ?
14007             defaultValue : this.state[name];
14008     },
14009     
14010     /**
14011      * Clears a value from the state
14012      * @param {String} name The key name
14013      */
14014     clear : function(name){
14015         delete this.state[name];
14016         this.fireEvent("statechange", this, name, null);
14017     },
14018     
14019     /**
14020      * Sets the value for a key
14021      * @param {String} name The key name
14022      * @param {Mixed} value The value to set
14023      */
14024     set : function(name, value){
14025         this.state[name] = value;
14026         this.fireEvent("statechange", this, name, value);
14027     },
14028     
14029     /**
14030      * Decodes a string previously encoded with {@link #encodeValue}.
14031      * @param {String} value The value to decode
14032      * @return {Mixed} The decoded value
14033      */
14034     decodeValue : function(cookie){
14035         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14036         var matches = re.exec(unescape(cookie));
14037         if(!matches || !matches[1]) return; // non state cookie
14038         var type = matches[1];
14039         var v = matches[2];
14040         switch(type){
14041             case "n":
14042                 return parseFloat(v);
14043             case "d":
14044                 return new Date(Date.parse(v));
14045             case "b":
14046                 return (v == "1");
14047             case "a":
14048                 var all = [];
14049                 var values = v.split("^");
14050                 for(var i = 0, len = values.length; i < len; i++){
14051                     all.push(this.decodeValue(values[i]));
14052                 }
14053                 return all;
14054            case "o":
14055                 var all = {};
14056                 var values = v.split("^");
14057                 for(var i = 0, len = values.length; i < len; i++){
14058                     var kv = values[i].split("=");
14059                     all[kv[0]] = this.decodeValue(kv[1]);
14060                 }
14061                 return all;
14062            default:
14063                 return v;
14064         }
14065     },
14066     
14067     /**
14068      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14069      * @param {Mixed} value The value to encode
14070      * @return {String} The encoded value
14071      */
14072     encodeValue : function(v){
14073         var enc;
14074         if(typeof v == "number"){
14075             enc = "n:" + v;
14076         }else if(typeof v == "boolean"){
14077             enc = "b:" + (v ? "1" : "0");
14078         }else if(v instanceof Date){
14079             enc = "d:" + v.toGMTString();
14080         }else if(v instanceof Array){
14081             var flat = "";
14082             for(var i = 0, len = v.length; i < len; i++){
14083                 flat += this.encodeValue(v[i]);
14084                 if(i != len-1) flat += "^";
14085             }
14086             enc = "a:" + flat;
14087         }else if(typeof v == "object"){
14088             var flat = "";
14089             for(var key in v){
14090                 if(typeof v[key] != "function"){
14091                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14092                 }
14093             }
14094             enc = "o:" + flat.substring(0, flat.length-1);
14095         }else{
14096             enc = "s:" + v;
14097         }
14098         return escape(enc);        
14099     }
14100 });
14101
14102 /*
14103  * Based on:
14104  * Ext JS Library 1.1.1
14105  * Copyright(c) 2006-2007, Ext JS, LLC.
14106  *
14107  * Originally Released Under LGPL - original licence link has changed is not relivant.
14108  *
14109  * Fork - LGPL
14110  * <script type="text/javascript">
14111  */
14112 /**
14113  * @class Roo.state.Manager
14114  * This is the global state manager. By default all components that are "state aware" check this class
14115  * for state information if you don't pass them a custom state provider. In order for this class
14116  * to be useful, it must be initialized with a provider when your application initializes.
14117  <pre><code>
14118 // in your initialization function
14119 init : function(){
14120    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14121    ...
14122    // supposed you have a {@link Roo.BorderLayout}
14123    var layout = new Roo.BorderLayout(...);
14124    layout.restoreState();
14125    // or a {Roo.BasicDialog}
14126    var dialog = new Roo.BasicDialog(...);
14127    dialog.restoreState();
14128  </code></pre>
14129  * @singleton
14130  */
14131 Roo.state.Manager = function(){
14132     var provider = new Roo.state.Provider();
14133     
14134     return {
14135         /**
14136          * Configures the default state provider for your application
14137          * @param {Provider} stateProvider The state provider to set
14138          */
14139         setProvider : function(stateProvider){
14140             provider = stateProvider;
14141         },
14142         
14143         /**
14144          * Returns the current value for a key
14145          * @param {String} name The key name
14146          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14147          * @return {Mixed} The state data
14148          */
14149         get : function(key, defaultValue){
14150             return provider.get(key, defaultValue);
14151         },
14152         
14153         /**
14154          * Sets the value for a key
14155          * @param {String} name The key name
14156          * @param {Mixed} value The state data
14157          */
14158          set : function(key, value){
14159             provider.set(key, value);
14160         },
14161         
14162         /**
14163          * Clears a value from the state
14164          * @param {String} name The key name
14165          */
14166         clear : function(key){
14167             provider.clear(key);
14168         },
14169         
14170         /**
14171          * Gets the currently configured state provider
14172          * @return {Provider} The state provider
14173          */
14174         getProvider : function(){
14175             return provider;
14176         }
14177     };
14178 }();
14179 /*
14180  * Based on:
14181  * Ext JS Library 1.1.1
14182  * Copyright(c) 2006-2007, Ext JS, LLC.
14183  *
14184  * Originally Released Under LGPL - original licence link has changed is not relivant.
14185  *
14186  * Fork - LGPL
14187  * <script type="text/javascript">
14188  */
14189 /**
14190  * @class Roo.state.CookieProvider
14191  * @extends Roo.state.Provider
14192  * The default Provider implementation which saves state via cookies.
14193  * <br />Usage:
14194  <pre><code>
14195    var cp = new Roo.state.CookieProvider({
14196        path: "/cgi-bin/",
14197        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14198        domain: "roojs.com"
14199    })
14200    Roo.state.Manager.setProvider(cp);
14201  </code></pre>
14202  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14203  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14204  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14205  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14206  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14207  * domain the page is running on including the 'www' like 'www.roojs.com')
14208  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14209  * @constructor
14210  * Create a new CookieProvider
14211  * @param {Object} config The configuration object
14212  */
14213 Roo.state.CookieProvider = function(config){
14214     Roo.state.CookieProvider.superclass.constructor.call(this);
14215     this.path = "/";
14216     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14217     this.domain = null;
14218     this.secure = false;
14219     Roo.apply(this, config);
14220     this.state = this.readCookies();
14221 };
14222
14223 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14224     // private
14225     set : function(name, value){
14226         if(typeof value == "undefined" || value === null){
14227             this.clear(name);
14228             return;
14229         }
14230         this.setCookie(name, value);
14231         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14232     },
14233
14234     // private
14235     clear : function(name){
14236         this.clearCookie(name);
14237         Roo.state.CookieProvider.superclass.clear.call(this, name);
14238     },
14239
14240     // private
14241     readCookies : function(){
14242         var cookies = {};
14243         var c = document.cookie + ";";
14244         var re = /\s?(.*?)=(.*?);/g;
14245         var matches;
14246         while((matches = re.exec(c)) != null){
14247             var name = matches[1];
14248             var value = matches[2];
14249             if(name && name.substring(0,3) == "ys-"){
14250                 cookies[name.substr(3)] = this.decodeValue(value);
14251             }
14252         }
14253         return cookies;
14254     },
14255
14256     // private
14257     setCookie : function(name, value){
14258         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14259            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14260            ((this.path == null) ? "" : ("; path=" + this.path)) +
14261            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14262            ((this.secure == true) ? "; secure" : "");
14263     },
14264
14265     // private
14266     clearCookie : function(name){
14267         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14268            ((this.path == null) ? "" : ("; path=" + this.path)) +
14269            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14270            ((this.secure == true) ? "; secure" : "");
14271     }
14272 });