roojs-core-debug.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * 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.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * 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]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618
619         /**
620          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621          * you may want to set this to true.
622          * @type Boolean
623          */
624         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
625         
626         
627                 
628         /**
629          * Selects a single element as a Roo Element
630          * This is about as close as you can get to jQuery's $('do crazy stuff')
631          * @param {String} selector The selector/xpath query
632          * @param {Node} root (optional) The start of the query (defaults to document).
633          * @return {Roo.Element}
634          */
635         selectNode : function(selector, root) 
636         {
637             var node = Roo.DomQuery.selectNode(selector,root);
638             return node ? Roo.get(node) : new Roo.Element(false);
639         }
640         
641     });
642
643
644 })();
645
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
648 /*
649  * Based on:
650  * Ext JS Library 1.1.1
651  * Copyright(c) 2006-2007, Ext JS, LLC.
652  *
653  * Originally Released Under LGPL - original licence link has changed is not relivant.
654  *
655  * Fork - LGPL
656  * <script type="text/javascript">
657  */
658
659 (function() {    
660     // wrappedn so fnCleanup is not in global scope...
661     if(Roo.isIE) {
662         function fnCleanUp() {
663             var p = Function.prototype;
664             delete p.createSequence;
665             delete p.defer;
666             delete p.createDelegate;
667             delete p.createCallback;
668             delete p.createInterceptor;
669
670             window.detachEvent("onunload", fnCleanUp);
671         }
672         window.attachEvent("onunload", fnCleanUp);
673     }
674 })();
675
676
677 /**
678  * @class Function
679  * These functions are available on every Function object (any JavaScript function).
680  */
681 Roo.apply(Function.prototype, {
682      /**
683      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685      * Will create a function that is bound to those 2 args.
686      * @return {Function} The new function
687     */
688     createCallback : function(/*args...*/){
689         // make args available, in function below
690         var args = arguments;
691         var method = this;
692         return function() {
693             return method.apply(window, args);
694         };
695     },
696
697     /**
698      * Creates a delegate (callback) that sets the scope to obj.
699      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700      * Will create a function that is automatically scoped to this.
701      * @param {Object} obj (optional) The object for which the scope is set
702      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704      *                                             if a number the args are inserted at the specified position
705      * @return {Function} The new function
706      */
707     createDelegate : function(obj, args, appendArgs){
708         var method = this;
709         return function() {
710             var callArgs = args || arguments;
711             if(appendArgs === true){
712                 callArgs = Array.prototype.slice.call(arguments, 0);
713                 callArgs = callArgs.concat(args);
714             }else if(typeof appendArgs == "number"){
715                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
718             }
719             return method.apply(obj || window, callArgs);
720         };
721     },
722
723     /**
724      * Calls this function after the number of millseconds specified.
725      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726      * @param {Object} obj (optional) The object for which the scope is set
727      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729      *                                             if a number the args are inserted at the specified position
730      * @return {Number} The timeout id that can be used with clearTimeout
731      */
732     defer : function(millis, obj, args, appendArgs){
733         var fn = this.createDelegate(obj, args, appendArgs);
734         if(millis){
735             return setTimeout(fn, millis);
736         }
737         fn();
738         return 0;
739     },
740     /**
741      * Create a combined function call sequence of the original function + the passed function.
742      * The resulting function returns the results of the original function.
743      * The passed fcn is called with the parameters of the original function
744      * @param {Function} fcn The function to sequence
745      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746      * @return {Function} The new function
747      */
748     createSequence : function(fcn, scope){
749         if(typeof fcn != "function"){
750             return this;
751         }
752         var method = this;
753         return function() {
754             var retval = method.apply(this || window, arguments);
755             fcn.apply(scope || this || window, arguments);
756             return retval;
757         };
758     },
759
760     /**
761      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762      * The resulting function returns the results of the original function.
763      * The passed fcn is called with the parameters of the original function.
764      * @addon
765      * @param {Function} fcn The function to call before the original
766      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767      * @return {Function} The new function
768      */
769     createInterceptor : function(fcn, scope){
770         if(typeof fcn != "function"){
771             return this;
772         }
773         var method = this;
774         return function() {
775             fcn.target = this;
776             fcn.method = method;
777             if(fcn.apply(scope || this || window, arguments) === false){
778                 return;
779             }
780             return method.apply(this || window, arguments);
781         };
782     }
783 });
784 /*
785  * Based on:
786  * Ext JS Library 1.1.1
787  * Copyright(c) 2006-2007, Ext JS, LLC.
788  *
789  * Originally Released Under LGPL - original licence link has changed is not relivant.
790  *
791  * Fork - LGPL
792  * <script type="text/javascript">
793  */
794
795 Roo.applyIf(String, {
796     
797     /** @scope String */
798     
799     /**
800      * Escapes the passed string for ' and \
801      * @param {String} string The string to escape
802      * @return {String} The escaped string
803      * @static
804      */
805     escape : function(string) {
806         return string.replace(/('|\\)/g, "\\$1");
807     },
808
809     /**
810      * Pads the left side of a string with a specified character.  This is especially useful
811      * for normalizing number and date strings.  Example usage:
812      * <pre><code>
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
815 </code></pre>
816      * @param {String} string The original string
817      * @param {Number} size The total length of the output string
818      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819      * @return {String} The padded string
820      * @static
821      */
822     leftPad : function (val, size, ch) {
823         var result = new String(val);
824         if(ch === null || ch === undefined || ch === '') {
825             ch = " ";
826         }
827         while (result.length < size) {
828             result = ch + result;
829         }
830         return result;
831     },
832
833     /**
834      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
835      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
836      * <pre><code>
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
840 </code></pre>
841      * @param {String} string The tokenized string to be formatted
842      * @param {String} value1 The value to replace token {0}
843      * @param {String} value2 Etc...
844      * @return {String} The formatted string
845      * @static
846      */
847     format : function(format){
848         var args = Array.prototype.slice.call(arguments, 1);
849         return format.replace(/\{(\d+)\}/g, function(m, i){
850             return Roo.util.Format.htmlEncode(args[i]);
851         });
852     }
853 });
854
855 /**
856  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
857  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
858  * they are already different, the first value passed in is returned.  Note that this method returns the new value
859  * but does not change the current string.
860  * <pre><code>
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
863
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
866 </code></pre>
867  * @param {String} value The value to compare to the current string
868  * @param {String} other The new value to use if the string already equals the first value passed in
869  * @return {String} The new value
870  */
871  
872 String.prototype.toggle = function(value, other){
873     return this == value ? other : value;
874 };/*
875  * Based on:
876  * Ext JS Library 1.1.1
877  * Copyright(c) 2006-2007, Ext JS, LLC.
878  *
879  * Originally Released Under LGPL - original licence link has changed is not relivant.
880  *
881  * Fork - LGPL
882  * <script type="text/javascript">
883  */
884
885  /**
886  * @class Number
887  */
888 Roo.applyIf(Number.prototype, {
889     /**
890      * Checks whether or not the current number is within a desired range.  If the number is already within the
891      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892      * exceeded.  Note that this method returns the constrained value but does not change the current number.
893      * @param {Number} min The minimum number in the range
894      * @param {Number} max The maximum number in the range
895      * @return {Number} The constrained value if outside the range, otherwise the current value
896      */
897     constrain : function(min, max){
898         return Math.min(Math.max(this, min), max);
899     }
900 });/*
901  * Based on:
902  * Ext JS Library 1.1.1
903  * Copyright(c) 2006-2007, Ext JS, LLC.
904  *
905  * Originally Released Under LGPL - original licence link has changed is not relivant.
906  *
907  * Fork - LGPL
908  * <script type="text/javascript">
909  */
910  /**
911  * @class Array
912  */
913 Roo.applyIf(Array.prototype, {
914     /**
915      * Checks whether or not the specified object exists in the array.
916      * @param {Object} o The object to check for
917      * @return {Number} The index of o in the array (or -1 if it is not found)
918      */
919     indexOf : function(o){
920        for (var i = 0, len = this.length; i < len; i++){
921               if(this[i] == o) return i;
922        }
923            return -1;
924     },
925
926     /**
927      * Removes the specified object from the array.  If the object is not found nothing happens.
928      * @param {Object} o The object to remove
929      */
930     remove : function(o){
931        var index = this.indexOf(o);
932        if(index != -1){
933            this.splice(index, 1);
934        }
935     },
936     /**
937      * Map (JS 1.6 compatibility)
938      * @param {Function} function  to call
939      */
940     map : function(fun )
941     {
942         var len = this.length >>> 0;
943         if (typeof fun != "function")
944             throw new TypeError();
945
946         var res = new Array(len);
947         var thisp = arguments[1];
948         for (var i = 0; i < len; i++)
949         {
950             if (i in this)
951                 res[i] = fun.call(thisp, this[i], i, this);
952         }
953
954         return res;
955     }
956     
957 });
958
959
960  /*
961  * Based on:
962  * Ext JS Library 1.1.1
963  * Copyright(c) 2006-2007, Ext JS, LLC.
964  *
965  * Originally Released Under LGPL - original licence link has changed is not relivant.
966  *
967  * Fork - LGPL
968  * <script type="text/javascript">
969  */
970
971 /**
972  * @class Date
973  *
974  * The date parsing and format syntax is a subset of
975  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976  * supported will provide results equivalent to their PHP versions.
977  *
978  * Following is the list of all currently supported formats:
979  *<pre>
980 Sample date:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
982
983 Format  Output      Description
984 ------  ----------  --------------------------------------------------------------
985   d      10         Day of the month, 2 digits with leading zeros
986   D      Wed        A textual representation of a day, three letters
987   j      10         Day of the month without leading zeros
988   l      Wednesday  A full textual representation of the day of the week
989   S      th         English ordinal day of month suffix, 2 chars (use with j)
990   w      3          Numeric representation of the day of the week
991   z      9          The julian date, or day of the year (0-365)
992   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993   F      January    A full textual representation of the month
994   m      01         Numeric representation of a month, with leading zeros
995   M      Jan        Month name abbreviation, three letters
996   n      1          Numeric representation of a month, without leading zeros
997   t      31         Number of days in the given month
998   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
999   Y      2007       A full numeric representation of a year, 4 digits
1000   y      07         A two digit representation of a year
1001   a      pm         Lowercase Ante meridiem and Post meridiem
1002   A      PM         Uppercase Ante meridiem and Post meridiem
1003   g      3          12-hour format of an hour without leading zeros
1004   G      15         24-hour format of an hour without leading zeros
1005   h      03         12-hour format of an hour with leading zeros
1006   H      15         24-hour format of an hour with leading zeros
1007   i      05         Minutes with leading zeros
1008   s      01         Seconds, with leading zeros
1009   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1010   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1011   T      CST        Timezone setting of the machine running the code
1012   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1013 </pre>
1014  *
1015  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1016  * <pre><code>
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d'));                         //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1020 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
1021  </code></pre>
1022  *
1023  * Here are some standard date/time patterns that you might find helpful.  They
1024  * are not part of the source of Date.js, but to use them you can simply copy this
1025  * block of code into any script that is included after Date.js and they will also become
1026  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1027  * <pre><code>
1028 Date.patterns = {
1029     ISO8601Long:"Y-m-d H:i:s",
1030     ISO8601Short:"Y-m-d",
1031     ShortDate: "n/j/Y",
1032     LongDate: "l, F d, Y",
1033     FullDateTime: "l, F d, Y g:i:s A",
1034     MonthDay: "F d",
1035     ShortTime: "g:i A",
1036     LongTime: "g:i:s A",
1037     SortableDateTime: "Y-m-d\\TH:i:s",
1038     UniversalSortableDateTime: "Y-m-d H:i:sO",
1039     YearMonth: "F, Y"
1040 };
1041 </code></pre>
1042  *
1043  * Example usage:
1044  * <pre><code>
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1047  </code></pre>
1048  */
1049
1050 /*
1051  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052  * They generate precompiled functions from date formats instead of parsing and
1053  * processing the pattern every time you format a date.  These functions are available
1054  * on every Date object (any javascript function).
1055  *
1056  * The original article and download are here:
1057  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1058  *
1059  */
1060  
1061  
1062  // was in core
1063 /**
1064  Returns the number of milliseconds between this date and date
1065  @param {Date} date (optional) Defaults to now
1066  @return {Number} The diff in milliseconds
1067  @member Date getElapsed
1068  */
1069 Date.prototype.getElapsed = function(date) {
1070         return Math.abs((date || new Date()).getTime()-this.getTime());
1071 };
1072 // was in date file..
1073
1074
1075 // private
1076 Date.parseFunctions = {count:0};
1077 // private
1078 Date.parseRegexes = [];
1079 // private
1080 Date.formatFunctions = {count:0};
1081
1082 // private
1083 Date.prototype.dateFormat = function(format) {
1084     if (Date.formatFunctions[format] == null) {
1085         Date.createNewFormat(format);
1086     }
1087     var func = Date.formatFunctions[format];
1088     return this[func]();
1089 };
1090
1091
1092 /**
1093  * Formats a date given the supplied format string
1094  * @param {String} format The format string
1095  * @return {String} The formatted date
1096  * @method
1097  */
1098 Date.prototype.format = Date.prototype.dateFormat;
1099
1100 // private
1101 Date.createNewFormat = function(format) {
1102     var funcName = "format" + Date.formatFunctions.count++;
1103     Date.formatFunctions[format] = funcName;
1104     var code = "Date.prototype." + funcName + " = function(){return ";
1105     var special = false;
1106     var ch = '';
1107     for (var i = 0; i < format.length; ++i) {
1108         ch = format.charAt(i);
1109         if (!special && ch == "\\") {
1110             special = true;
1111         }
1112         else if (special) {
1113             special = false;
1114             code += "'" + String.escape(ch) + "' + ";
1115         }
1116         else {
1117             code += Date.getFormatCode(ch);
1118         }
1119     }
1120     /** eval:var:zzzzzzzzzzzzz */
1121     eval(code.substring(0, code.length - 3) + ";}");
1122 };
1123
1124 // private
1125 Date.getFormatCode = function(character) {
1126     switch (character) {
1127     case "d":
1128         return "String.leftPad(this.getDate(), 2, '0') + ";
1129     case "D":
1130         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1131     case "j":
1132         return "this.getDate() + ";
1133     case "l":
1134         return "Date.dayNames[this.getDay()] + ";
1135     case "S":
1136         return "this.getSuffix() + ";
1137     case "w":
1138         return "this.getDay() + ";
1139     case "z":
1140         return "this.getDayOfYear() + ";
1141     case "W":
1142         return "this.getWeekOfYear() + ";
1143     case "F":
1144         return "Date.monthNames[this.getMonth()] + ";
1145     case "m":
1146         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1147     case "M":
1148         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1149     case "n":
1150         return "(this.getMonth() + 1) + ";
1151     case "t":
1152         return "this.getDaysInMonth() + ";
1153     case "L":
1154         return "(this.isLeapYear() ? 1 : 0) + ";
1155     case "Y":
1156         return "this.getFullYear() + ";
1157     case "y":
1158         return "('' + this.getFullYear()).substring(2, 4) + ";
1159     case "a":
1160         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1161     case "A":
1162         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1163     case "g":
1164         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1165     case "G":
1166         return "this.getHours() + ";
1167     case "h":
1168         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1169     case "H":
1170         return "String.leftPad(this.getHours(), 2, '0') + ";
1171     case "i":
1172         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1173     case "s":
1174         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1175     case "O":
1176         return "this.getGMTOffset() + ";
1177     case "P":
1178         return "this.getGMTColonOffset() + ";
1179     case "T":
1180         return "this.getTimezone() + ";
1181     case "Z":
1182         return "(this.getTimezoneOffset() * -60) + ";
1183     default:
1184         return "'" + String.escape(character) + "' + ";
1185     }
1186 };
1187
1188 /**
1189  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1191  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1192  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1193  * string or the parse operation will fail.
1194  * Example Usage:
1195 <pre><code>
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1198
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1201
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1204
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1207 </code></pre>
1208  * @param {String} input The unparsed date as a string
1209  * @param {String} format The format the date is in
1210  * @return {Date} The parsed date
1211  * @static
1212  */
1213 Date.parseDate = function(input, format) {
1214     if (Date.parseFunctions[format] == null) {
1215         Date.createParser(format);
1216     }
1217     var func = Date.parseFunctions[format];
1218     return Date[func](input);
1219 };
1220 /**
1221  * @private
1222  */
1223 Date.createParser = function(format) {
1224     var funcName = "parse" + Date.parseFunctions.count++;
1225     var regexNum = Date.parseRegexes.length;
1226     var currentGroup = 1;
1227     Date.parseFunctions[format] = funcName;
1228
1229     var code = "Date." + funcName + " = function(input){\n"
1230         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231         + "var d = new Date();\n"
1232         + "y = d.getFullYear();\n"
1233         + "m = d.getMonth();\n"
1234         + "d = d.getDate();\n"
1235         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236         + "if (results && results.length > 0) {";
1237     var regex = "";
1238
1239     var special = false;
1240     var ch = '';
1241     for (var i = 0; i < format.length; ++i) {
1242         ch = format.charAt(i);
1243         if (!special && ch == "\\") {
1244             special = true;
1245         }
1246         else if (special) {
1247             special = false;
1248             regex += String.escape(ch);
1249         }
1250         else {
1251             var obj = Date.formatCodeToRegex(ch, currentGroup);
1252             currentGroup += obj.g;
1253             regex += obj.s;
1254             if (obj.g && obj.c) {
1255                 code += obj.c;
1256             }
1257         }
1258     }
1259
1260     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261         + "{v = new Date(y, m, d, h, i, s);}\n"
1262         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265         + "{v = new Date(y, m, d, h);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267         + "{v = new Date(y, m, d);}\n"
1268         + "else if (y >= 0 && m >= 0)\n"
1269         + "{v = new Date(y, m);}\n"
1270         + "else if (y >= 0)\n"
1271         + "{v = new Date(y);}\n"
1272         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1275         + ";}";
1276
1277     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278     /** eval:var:zzzzzzzzzzzzz */
1279     eval(code);
1280 };
1281
1282 // private
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284     switch (character) {
1285     case "D":
1286         return {g:0,
1287         c:null,
1288         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1289     case "j":
1290         return {g:1,
1291             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292             s:"(\\d{1,2})"}; // day of month without leading zeroes
1293     case "d":
1294         return {g:1,
1295             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296             s:"(\\d{2})"}; // day of month with leading zeroes
1297     case "l":
1298         return {g:0,
1299             c:null,
1300             s:"(?:" + Date.dayNames.join("|") + ")"};
1301     case "S":
1302         return {g:0,
1303             c:null,
1304             s:"(?:st|nd|rd|th)"};
1305     case "w":
1306         return {g:0,
1307             c:null,
1308             s:"\\d"};
1309     case "z":
1310         return {g:0,
1311             c:null,
1312             s:"(?:\\d{1,3})"};
1313     case "W":
1314         return {g:0,
1315             c:null,
1316             s:"(?:\\d{2})"};
1317     case "F":
1318         return {g:1,
1319             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320             s:"(" + Date.monthNames.join("|") + ")"};
1321     case "M":
1322         return {g:1,
1323             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1325     case "n":
1326         return {g:1,
1327             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1329     case "m":
1330         return {g:1,
1331             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1333     case "t":
1334         return {g:0,
1335             c:null,
1336             s:"\\d{1,2}"};
1337     case "L":
1338         return {g:0,
1339             c:null,
1340             s:"(?:1|0)"};
1341     case "Y":
1342         return {g:1,
1343             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1344             s:"(\\d{4})"};
1345     case "y":
1346         return {g:1,
1347             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1349             s:"(\\d{1,2})"};
1350     case "a":
1351         return {g:1,
1352             c:"if (results[" + currentGroup + "] == 'am') {\n"
1353                 + "if (h == 12) { h = 0; }\n"
1354                 + "} else { if (h < 12) { h += 12; }}",
1355             s:"(am|pm)"};
1356     case "A":
1357         return {g:1,
1358             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359                 + "if (h == 12) { h = 0; }\n"
1360                 + "} else { if (h < 12) { h += 12; }}",
1361             s:"(AM|PM)"};
1362     case "g":
1363     case "G":
1364         return {g:1,
1365             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1367     case "h":
1368     case "H":
1369         return {g:1,
1370             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1372     case "i":
1373         return {g:1,
1374             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1375             s:"(\\d{2})"};
1376     case "s":
1377         return {g:1,
1378             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1379             s:"(\\d{2})"};
1380     case "O":
1381         return {g:1,
1382             c:[
1383                 "o = results[", currentGroup, "];\n",
1384                 "var sn = o.substring(0,1);\n", // get + / - sign
1385                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1389             ].join(""),
1390             s:"([+\-]\\d{2,4})"};
1391     
1392     
1393     case "P":
1394         return {g:1,
1395                 c:[
1396                    "o = results[", currentGroup, "];\n",
1397                    "var sn = o.substring(0,1);\n",
1398                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1399                    "var mn = o.substring(4,6) % 60;\n",
1400                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1401                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1402             ].join(""),
1403             s:"([+\-]\\d{4})"};
1404     case "T":
1405         return {g:0,
1406             c:null,
1407             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1408     case "Z":
1409         return {g:1,
1410             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1411                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1412             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1413     default:
1414         return {g:0,
1415             c:null,
1416             s:String.escape(character)};
1417     }
1418 };
1419
1420 /**
1421  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1422  * @return {String} The abbreviated timezone name (e.g. 'CST')
1423  */
1424 Date.prototype.getTimezone = function() {
1425     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1426 };
1427
1428 /**
1429  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1430  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1431  */
1432 Date.prototype.getGMTOffset = function() {
1433     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1434         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1435         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1436 };
1437
1438 /**
1439  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1440  * @return {String} 2-characters representing hours and 2-characters representing minutes
1441  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1442  */
1443 Date.prototype.getGMTColonOffset = function() {
1444         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1445                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1446                 + ":"
1447                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1448 }
1449
1450 /**
1451  * Get the numeric day number of the year, adjusted for leap year.
1452  * @return {Number} 0 through 364 (365 in leap years)
1453  */
1454 Date.prototype.getDayOfYear = function() {
1455     var num = 0;
1456     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1457     for (var i = 0; i < this.getMonth(); ++i) {
1458         num += Date.daysInMonth[i];
1459     }
1460     return num + this.getDate() - 1;
1461 };
1462
1463 /**
1464  * Get the string representation of the numeric week number of the year
1465  * (equivalent to the format specifier 'W').
1466  * @return {String} '00' through '52'
1467  */
1468 Date.prototype.getWeekOfYear = function() {
1469     // Skip to Thursday of this week
1470     var now = this.getDayOfYear() + (4 - this.getDay());
1471     // Find the first Thursday of the year
1472     var jan1 = new Date(this.getFullYear(), 0, 1);
1473     var then = (7 - jan1.getDay() + 4);
1474     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1475 };
1476
1477 /**
1478  * Whether or not the current date is in a leap year.
1479  * @return {Boolean} True if the current date is in a leap year, else false
1480  */
1481 Date.prototype.isLeapYear = function() {
1482     var year = this.getFullYear();
1483     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1484 };
1485
1486 /**
1487  * Get the first day of the current month, adjusted for leap year.  The returned value
1488  * is the numeric day index within the week (0-6) which can be used in conjunction with
1489  * the {@link #monthNames} array to retrieve the textual day name.
1490  * Example:
1491  *<pre><code>
1492 var dt = new Date('1/10/2007');
1493 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1494 </code></pre>
1495  * @return {Number} The day number (0-6)
1496  */
1497 Date.prototype.getFirstDayOfMonth = function() {
1498     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1499     return (day < 0) ? (day + 7) : day;
1500 };
1501
1502 /**
1503  * Get the last day of the current month, adjusted for leap year.  The returned value
1504  * is the numeric day index within the week (0-6) which can be used in conjunction with
1505  * the {@link #monthNames} array to retrieve the textual day name.
1506  * Example:
1507  *<pre><code>
1508 var dt = new Date('1/10/2007');
1509 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1510 </code></pre>
1511  * @return {Number} The day number (0-6)
1512  */
1513 Date.prototype.getLastDayOfMonth = function() {
1514     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1515     return (day < 0) ? (day + 7) : day;
1516 };
1517
1518
1519 /**
1520  * Get the first date of this date's month
1521  * @return {Date}
1522  */
1523 Date.prototype.getFirstDateOfMonth = function() {
1524     return new Date(this.getFullYear(), this.getMonth(), 1);
1525 };
1526
1527 /**
1528  * Get the last date of this date's month
1529  * @return {Date}
1530  */
1531 Date.prototype.getLastDateOfMonth = function() {
1532     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1533 };
1534 /**
1535  * Get the number of days in the current month, adjusted for leap year.
1536  * @return {Number} The number of days in the month
1537  */
1538 Date.prototype.getDaysInMonth = function() {
1539     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1540     return Date.daysInMonth[this.getMonth()];
1541 };
1542
1543 /**
1544  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1545  * @return {String} 'st, 'nd', 'rd' or 'th'
1546  */
1547 Date.prototype.getSuffix = function() {
1548     switch (this.getDate()) {
1549         case 1:
1550         case 21:
1551         case 31:
1552             return "st";
1553         case 2:
1554         case 22:
1555             return "nd";
1556         case 3:
1557         case 23:
1558             return "rd";
1559         default:
1560             return "th";
1561     }
1562 };
1563
1564 // private
1565 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1566
1567 /**
1568  * An array of textual month names.
1569  * Override these values for international dates, for example...
1570  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1571  * @type Array
1572  * @static
1573  */
1574 Date.monthNames =
1575    ["January",
1576     "February",
1577     "March",
1578     "April",
1579     "May",
1580     "June",
1581     "July",
1582     "August",
1583     "September",
1584     "October",
1585     "November",
1586     "December"];
1587
1588 /**
1589  * An array of textual day names.
1590  * Override these values for international dates, for example...
1591  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1592  * @type Array
1593  * @static
1594  */
1595 Date.dayNames =
1596    ["Sunday",
1597     "Monday",
1598     "Tuesday",
1599     "Wednesday",
1600     "Thursday",
1601     "Friday",
1602     "Saturday"];
1603
1604 // private
1605 Date.y2kYear = 50;
1606 // private
1607 Date.monthNumbers = {
1608     Jan:0,
1609     Feb:1,
1610     Mar:2,
1611     Apr:3,
1612     May:4,
1613     Jun:5,
1614     Jul:6,
1615     Aug:7,
1616     Sep:8,
1617     Oct:9,
1618     Nov:10,
1619     Dec:11};
1620
1621 /**
1622  * Creates and returns a new Date instance with the exact same date value as the called instance.
1623  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1624  * variable will also be changed.  When the intention is to create a new variable that will not
1625  * modify the original instance, you should create a clone.
1626  *
1627  * Example of correctly cloning a date:
1628  * <pre><code>
1629 //wrong way:
1630 var orig = new Date('10/1/2006');
1631 var copy = orig;
1632 copy.setDate(5);
1633 document.write(orig);  //returns 'Thu Oct 05 2006'!
1634
1635 //correct way:
1636 var orig = new Date('10/1/2006');
1637 var copy = orig.clone();
1638 copy.setDate(5);
1639 document.write(orig);  //returns 'Thu Oct 01 2006'
1640 </code></pre>
1641  * @return {Date} The new Date instance
1642  */
1643 Date.prototype.clone = function() {
1644         return new Date(this.getTime());
1645 };
1646
1647 /**
1648  * Clears any time information from this date
1649  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1650  @return {Date} this or the clone
1651  */
1652 Date.prototype.clearTime = function(clone){
1653     if(clone){
1654         return this.clone().clearTime();
1655     }
1656     this.setHours(0);
1657     this.setMinutes(0);
1658     this.setSeconds(0);
1659     this.setMilliseconds(0);
1660     return this;
1661 };
1662
1663 // private
1664 // safari setMonth is broken
1665 if(Roo.isSafari){
1666     Date.brokenSetMonth = Date.prototype.setMonth;
1667         Date.prototype.setMonth = function(num){
1668                 if(num <= -1){
1669                         var n = Math.ceil(-num);
1670                         var back_year = Math.ceil(n/12);
1671                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1672                         this.setFullYear(this.getFullYear() - back_year);
1673                         return Date.brokenSetMonth.call(this, month);
1674                 } else {
1675                         return Date.brokenSetMonth.apply(this, arguments);
1676                 }
1677         };
1678 }
1679
1680 /** Date interval constant 
1681 * @static 
1682 * @type String */
1683 Date.MILLI = "ms";
1684 /** Date interval constant 
1685 * @static 
1686 * @type String */
1687 Date.SECOND = "s";
1688 /** Date interval constant 
1689 * @static 
1690 * @type String */
1691 Date.MINUTE = "mi";
1692 /** Date interval constant 
1693 * @static 
1694 * @type String */
1695 Date.HOUR = "h";
1696 /** Date interval constant 
1697 * @static 
1698 * @type String */
1699 Date.DAY = "d";
1700 /** Date interval constant 
1701 * @static 
1702 * @type String */
1703 Date.MONTH = "mo";
1704 /** Date interval constant 
1705 * @static 
1706 * @type String */
1707 Date.YEAR = "y";
1708
1709 /**
1710  * Provides a convenient method of performing basic date arithmetic.  This method
1711  * does not modify the Date instance being called - it creates and returns
1712  * a new Date instance containing the resulting date value.
1713  *
1714  * Examples:
1715  * <pre><code>
1716 //Basic usage:
1717 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1718 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1719
1720 //Negative values will subtract correctly:
1721 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1722 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1723
1724 //You can even chain several calls together in one line!
1725 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1726 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1727  </code></pre>
1728  *
1729  * @param {String} interval   A valid date interval enum value
1730  * @param {Number} value      The amount to add to the current date
1731  * @return {Date} The new Date instance
1732  */
1733 Date.prototype.add = function(interval, value){
1734   var d = this.clone();
1735   if (!interval || value === 0) return d;
1736   switch(interval.toLowerCase()){
1737     case Date.MILLI:
1738       d.setMilliseconds(this.getMilliseconds() + value);
1739       break;
1740     case Date.SECOND:
1741       d.setSeconds(this.getSeconds() + value);
1742       break;
1743     case Date.MINUTE:
1744       d.setMinutes(this.getMinutes() + value);
1745       break;
1746     case Date.HOUR:
1747       d.setHours(this.getHours() + value);
1748       break;
1749     case Date.DAY:
1750       d.setDate(this.getDate() + value);
1751       break;
1752     case Date.MONTH:
1753       var day = this.getDate();
1754       if(day > 28){
1755           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1756       }
1757       d.setDate(day);
1758       d.setMonth(this.getMonth() + value);
1759       break;
1760     case Date.YEAR:
1761       d.setFullYear(this.getFullYear() + value);
1762       break;
1763   }
1764   return d;
1765 };
1766 /*
1767  * Based on:
1768  * Ext JS Library 1.1.1
1769  * Copyright(c) 2006-2007, Ext JS, LLC.
1770  *
1771  * Originally Released Under LGPL - original licence link has changed is not relivant.
1772  *
1773  * Fork - LGPL
1774  * <script type="text/javascript">
1775  */
1776
1777 /**
1778  * @class Roo.lib.Dom
1779  * @static
1780  * 
1781  * Dom utils (from YIU afaik)
1782  * 
1783  **/
1784 Roo.lib.Dom = {
1785     /**
1786      * Get the view width
1787      * @param {Boolean} full True will get the full document, otherwise it's the view width
1788      * @return {Number} The width
1789      */
1790      
1791     getViewWidth : function(full) {
1792         return full ? this.getDocumentWidth() : this.getViewportWidth();
1793     },
1794     /**
1795      * Get the view height
1796      * @param {Boolean} full True will get the full document, otherwise it's the view height
1797      * @return {Number} The height
1798      */
1799     getViewHeight : function(full) {
1800         return full ? this.getDocumentHeight() : this.getViewportHeight();
1801     },
1802
1803     getDocumentHeight: function() {
1804         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1805         return Math.max(scrollHeight, this.getViewportHeight());
1806     },
1807
1808     getDocumentWidth: function() {
1809         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1810         return Math.max(scrollWidth, this.getViewportWidth());
1811     },
1812
1813     getViewportHeight: function() {
1814         var height = self.innerHeight;
1815         var mode = document.compatMode;
1816
1817         if ((mode || Roo.isIE) && !Roo.isOpera) {
1818             height = (mode == "CSS1Compat") ?
1819                      document.documentElement.clientHeight :
1820                      document.body.clientHeight;
1821         }
1822
1823         return height;
1824     },
1825
1826     getViewportWidth: function() {
1827         var width = self.innerWidth;
1828         var mode = document.compatMode;
1829
1830         if (mode || Roo.isIE) {
1831             width = (mode == "CSS1Compat") ?
1832                     document.documentElement.clientWidth :
1833                     document.body.clientWidth;
1834         }
1835         return width;
1836     },
1837
1838     isAncestor : function(p, c) {
1839         p = Roo.getDom(p);
1840         c = Roo.getDom(c);
1841         if (!p || !c) {
1842             return false;
1843         }
1844
1845         if (p.contains && !Roo.isSafari) {
1846             return p.contains(c);
1847         } else if (p.compareDocumentPosition) {
1848             return !!(p.compareDocumentPosition(c) & 16);
1849         } else {
1850             var parent = c.parentNode;
1851             while (parent) {
1852                 if (parent == p) {
1853                     return true;
1854                 }
1855                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1856                     return false;
1857                 }
1858                 parent = parent.parentNode;
1859             }
1860             return false;
1861         }
1862     },
1863
1864     getRegion : function(el) {
1865         return Roo.lib.Region.getRegion(el);
1866     },
1867
1868     getY : function(el) {
1869         return this.getXY(el)[1];
1870     },
1871
1872     getX : function(el) {
1873         return this.getXY(el)[0];
1874     },
1875
1876     getXY : function(el) {
1877         var p, pe, b, scroll, bd = document.body;
1878         el = Roo.getDom(el);
1879         var fly = Roo.lib.AnimBase.fly;
1880         if (el.getBoundingClientRect) {
1881             b = el.getBoundingClientRect();
1882             scroll = fly(document).getScroll();
1883             return [b.left + scroll.left, b.top + scroll.top];
1884         }
1885         var x = 0, y = 0;
1886
1887         p = el;
1888
1889         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1890
1891         while (p) {
1892
1893             x += p.offsetLeft;
1894             y += p.offsetTop;
1895
1896             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1897                 hasAbsolute = true;
1898             }
1899
1900             if (Roo.isGecko) {
1901                 pe = fly(p);
1902
1903                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1904                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1905
1906
1907                 x += bl;
1908                 y += bt;
1909
1910
1911                 if (p != el && pe.getStyle('overflow') != 'visible') {
1912                     x += bl;
1913                     y += bt;
1914                 }
1915             }
1916             p = p.offsetParent;
1917         }
1918
1919         if (Roo.isSafari && hasAbsolute) {
1920             x -= bd.offsetLeft;
1921             y -= bd.offsetTop;
1922         }
1923
1924         if (Roo.isGecko && !hasAbsolute) {
1925             var dbd = fly(bd);
1926             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1927             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1928         }
1929
1930         p = el.parentNode;
1931         while (p && p != bd) {
1932             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1933                 x -= p.scrollLeft;
1934                 y -= p.scrollTop;
1935             }
1936             p = p.parentNode;
1937         }
1938         return [x, y];
1939     },
1940  
1941   
1942
1943
1944     setXY : function(el, xy) {
1945         el = Roo.fly(el, '_setXY');
1946         el.position();
1947         var pts = el.translatePoints(xy);
1948         if (xy[0] !== false) {
1949             el.dom.style.left = pts.left + "px";
1950         }
1951         if (xy[1] !== false) {
1952             el.dom.style.top = pts.top + "px";
1953         }
1954     },
1955
1956     setX : function(el, x) {
1957         this.setXY(el, [x, false]);
1958     },
1959
1960     setY : function(el, y) {
1961         this.setXY(el, [false, y]);
1962     }
1963 };
1964 /*
1965  * Portions of this file are based on pieces of Yahoo User Interface Library
1966  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1967  * YUI licensed under the BSD License:
1968  * http://developer.yahoo.net/yui/license.txt
1969  * <script type="text/javascript">
1970  *
1971  */
1972
1973 Roo.lib.Event = function() {
1974     var loadComplete = false;
1975     var listeners = [];
1976     var unloadListeners = [];
1977     var retryCount = 0;
1978     var onAvailStack = [];
1979     var counter = 0;
1980     var lastError = null;
1981
1982     return {
1983         POLL_RETRYS: 200,
1984         POLL_INTERVAL: 20,
1985         EL: 0,
1986         TYPE: 1,
1987         FN: 2,
1988         WFN: 3,
1989         OBJ: 3,
1990         ADJ_SCOPE: 4,
1991         _interval: null,
1992
1993         startInterval: function() {
1994             if (!this._interval) {
1995                 var self = this;
1996                 var callback = function() {
1997                     self._tryPreloadAttach();
1998                 };
1999                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2000
2001             }
2002         },
2003
2004         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2005             onAvailStack.push({ id:         p_id,
2006                 fn:         p_fn,
2007                 obj:        p_obj,
2008                 override:   p_override,
2009                 checkReady: false    });
2010
2011             retryCount = this.POLL_RETRYS;
2012             this.startInterval();
2013         },
2014
2015
2016         addListener: function(el, eventName, fn) {
2017             el = Roo.getDom(el);
2018             if (!el || !fn) {
2019                 return false;
2020             }
2021
2022             if ("unload" == eventName) {
2023                 unloadListeners[unloadListeners.length] =
2024                 [el, eventName, fn];
2025                 return true;
2026             }
2027
2028             var wrappedFn = function(e) {
2029                 return fn(Roo.lib.Event.getEvent(e));
2030             };
2031
2032             var li = [el, eventName, fn, wrappedFn];
2033
2034             var index = listeners.length;
2035             listeners[index] = li;
2036
2037             this.doAdd(el, eventName, wrappedFn, false);
2038             return true;
2039
2040         },
2041
2042
2043         removeListener: function(el, eventName, fn) {
2044             var i, len;
2045
2046             el = Roo.getDom(el);
2047
2048             if(!fn) {
2049                 return this.purgeElement(el, false, eventName);
2050             }
2051
2052
2053             if ("unload" == eventName) {
2054
2055                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2056                     var li = unloadListeners[i];
2057                     if (li &&
2058                         li[0] == el &&
2059                         li[1] == eventName &&
2060                         li[2] == fn) {
2061                         unloadListeners.splice(i, 1);
2062                         return true;
2063                     }
2064                 }
2065
2066                 return false;
2067             }
2068
2069             var cacheItem = null;
2070
2071
2072             var index = arguments[3];
2073
2074             if ("undefined" == typeof index) {
2075                 index = this._getCacheIndex(el, eventName, fn);
2076             }
2077
2078             if (index >= 0) {
2079                 cacheItem = listeners[index];
2080             }
2081
2082             if (!el || !cacheItem) {
2083                 return false;
2084             }
2085
2086             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2087
2088             delete listeners[index][this.WFN];
2089             delete listeners[index][this.FN];
2090             listeners.splice(index, 1);
2091
2092             return true;
2093
2094         },
2095
2096
2097         getTarget: function(ev, resolveTextNode) {
2098             ev = ev.browserEvent || ev;
2099             var t = ev.target || ev.srcElement;
2100             return this.resolveTextNode(t);
2101         },
2102
2103
2104         resolveTextNode: function(node) {
2105             if (Roo.isSafari && node && 3 == node.nodeType) {
2106                 return node.parentNode;
2107             } else {
2108                 return node;
2109             }
2110         },
2111
2112
2113         getPageX: function(ev) {
2114             ev = ev.browserEvent || ev;
2115             var x = ev.pageX;
2116             if (!x && 0 !== x) {
2117                 x = ev.clientX || 0;
2118
2119                 if (Roo.isIE) {
2120                     x += this.getScroll()[1];
2121                 }
2122             }
2123
2124             return x;
2125         },
2126
2127
2128         getPageY: function(ev) {
2129             ev = ev.browserEvent || ev;
2130             var y = ev.pageY;
2131             if (!y && 0 !== y) {
2132                 y = ev.clientY || 0;
2133
2134                 if (Roo.isIE) {
2135                     y += this.getScroll()[0];
2136                 }
2137             }
2138
2139
2140             return y;
2141         },
2142
2143
2144         getXY: function(ev) {
2145             ev = ev.browserEvent || ev;
2146             return [this.getPageX(ev), this.getPageY(ev)];
2147         },
2148
2149
2150         getRelatedTarget: function(ev) {
2151             ev = ev.browserEvent || ev;
2152             var t = ev.relatedTarget;
2153             if (!t) {
2154                 if (ev.type == "mouseout") {
2155                     t = ev.toElement;
2156                 } else if (ev.type == "mouseover") {
2157                     t = ev.fromElement;
2158                 }
2159             }
2160
2161             return this.resolveTextNode(t);
2162         },
2163
2164
2165         getTime: function(ev) {
2166             ev = ev.browserEvent || ev;
2167             if (!ev.time) {
2168                 var t = new Date().getTime();
2169                 try {
2170                     ev.time = t;
2171                 } catch(ex) {
2172                     this.lastError = ex;
2173                     return t;
2174                 }
2175             }
2176
2177             return ev.time;
2178         },
2179
2180
2181         stopEvent: function(ev) {
2182             this.stopPropagation(ev);
2183             this.preventDefault(ev);
2184         },
2185
2186
2187         stopPropagation: function(ev) {
2188             ev = ev.browserEvent || ev;
2189             if (ev.stopPropagation) {
2190                 ev.stopPropagation();
2191             } else {
2192                 ev.cancelBubble = true;
2193             }
2194         },
2195
2196
2197         preventDefault: function(ev) {
2198             ev = ev.browserEvent || ev;
2199             if(ev.preventDefault) {
2200                 ev.preventDefault();
2201             } else {
2202                 ev.returnValue = false;
2203             }
2204         },
2205
2206
2207         getEvent: function(e) {
2208             var ev = e || window.event;
2209             if (!ev) {
2210                 var c = this.getEvent.caller;
2211                 while (c) {
2212                     ev = c.arguments[0];
2213                     if (ev && Event == ev.constructor) {
2214                         break;
2215                     }
2216                     c = c.caller;
2217                 }
2218             }
2219             return ev;
2220         },
2221
2222
2223         getCharCode: function(ev) {
2224             ev = ev.browserEvent || ev;
2225             return ev.charCode || ev.keyCode || 0;
2226         },
2227
2228
2229         _getCacheIndex: function(el, eventName, fn) {
2230             for (var i = 0,len = listeners.length; i < len; ++i) {
2231                 var li = listeners[i];
2232                 if (li &&
2233                     li[this.FN] == fn &&
2234                     li[this.EL] == el &&
2235                     li[this.TYPE] == eventName) {
2236                     return i;
2237                 }
2238             }
2239
2240             return -1;
2241         },
2242
2243
2244         elCache: {},
2245
2246
2247         getEl: function(id) {
2248             return document.getElementById(id);
2249         },
2250
2251
2252         clearCache: function() {
2253         },
2254
2255
2256         _load: function(e) {
2257             loadComplete = true;
2258             var EU = Roo.lib.Event;
2259
2260
2261             if (Roo.isIE) {
2262                 EU.doRemove(window, "load", EU._load);
2263             }
2264         },
2265
2266
2267         _tryPreloadAttach: function() {
2268
2269             if (this.locked) {
2270                 return false;
2271             }
2272
2273             this.locked = true;
2274
2275
2276             var tryAgain = !loadComplete;
2277             if (!tryAgain) {
2278                 tryAgain = (retryCount > 0);
2279             }
2280
2281
2282             var notAvail = [];
2283             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2284                 var item = onAvailStack[i];
2285                 if (item) {
2286                     var el = this.getEl(item.id);
2287
2288                     if (el) {
2289                         if (!item.checkReady ||
2290                             loadComplete ||
2291                             el.nextSibling ||
2292                             (document && document.body)) {
2293
2294                             var scope = el;
2295                             if (item.override) {
2296                                 if (item.override === true) {
2297                                     scope = item.obj;
2298                                 } else {
2299                                     scope = item.override;
2300                                 }
2301                             }
2302                             item.fn.call(scope, item.obj);
2303                             onAvailStack[i] = null;
2304                         }
2305                     } else {
2306                         notAvail.push(item);
2307                     }
2308                 }
2309             }
2310
2311             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2312
2313             if (tryAgain) {
2314
2315                 this.startInterval();
2316             } else {
2317                 clearInterval(this._interval);
2318                 this._interval = null;
2319             }
2320
2321             this.locked = false;
2322
2323             return true;
2324
2325         },
2326
2327
2328         purgeElement: function(el, recurse, eventName) {
2329             var elListeners = this.getListeners(el, eventName);
2330             if (elListeners) {
2331                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2332                     var l = elListeners[i];
2333                     this.removeListener(el, l.type, l.fn);
2334                 }
2335             }
2336
2337             if (recurse && el && el.childNodes) {
2338                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2339                     this.purgeElement(el.childNodes[i], recurse, eventName);
2340                 }
2341             }
2342         },
2343
2344
2345         getListeners: function(el, eventName) {
2346             var results = [], searchLists;
2347             if (!eventName) {
2348                 searchLists = [listeners, unloadListeners];
2349             } else if (eventName == "unload") {
2350                 searchLists = [unloadListeners];
2351             } else {
2352                 searchLists = [listeners];
2353             }
2354
2355             for (var j = 0; j < searchLists.length; ++j) {
2356                 var searchList = searchLists[j];
2357                 if (searchList && searchList.length > 0) {
2358                     for (var i = 0,len = searchList.length; i < len; ++i) {
2359                         var l = searchList[i];
2360                         if (l && l[this.EL] === el &&
2361                             (!eventName || eventName === l[this.TYPE])) {
2362                             results.push({
2363                                 type:   l[this.TYPE],
2364                                 fn:     l[this.FN],
2365                                 obj:    l[this.OBJ],
2366                                 adjust: l[this.ADJ_SCOPE],
2367                                 index:  i
2368                             });
2369                         }
2370                     }
2371                 }
2372             }
2373
2374             return (results.length) ? results : null;
2375         },
2376
2377
2378         _unload: function(e) {
2379
2380             var EU = Roo.lib.Event, i, j, l, len, index;
2381
2382             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2383                 l = unloadListeners[i];
2384                 if (l) {
2385                     var scope = window;
2386                     if (l[EU.ADJ_SCOPE]) {
2387                         if (l[EU.ADJ_SCOPE] === true) {
2388                             scope = l[EU.OBJ];
2389                         } else {
2390                             scope = l[EU.ADJ_SCOPE];
2391                         }
2392                     }
2393                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2394                     unloadListeners[i] = null;
2395                     l = null;
2396                     scope = null;
2397                 }
2398             }
2399
2400             unloadListeners = null;
2401
2402             if (listeners && listeners.length > 0) {
2403                 j = listeners.length;
2404                 while (j) {
2405                     index = j - 1;
2406                     l = listeners[index];
2407                     if (l) {
2408                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2409                                 l[EU.FN], index);
2410                     }
2411                     j = j - 1;
2412                 }
2413                 l = null;
2414
2415                 EU.clearCache();
2416             }
2417
2418             EU.doRemove(window, "unload", EU._unload);
2419
2420         },
2421
2422
2423         getScroll: function() {
2424             var dd = document.documentElement, db = document.body;
2425             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2426                 return [dd.scrollTop, dd.scrollLeft];
2427             } else if (db) {
2428                 return [db.scrollTop, db.scrollLeft];
2429             } else {
2430                 return [0, 0];
2431             }
2432         },
2433
2434
2435         doAdd: function () {
2436             if (window.addEventListener) {
2437                 return function(el, eventName, fn, capture) {
2438                     el.addEventListener(eventName, fn, (capture));
2439                 };
2440             } else if (window.attachEvent) {
2441                 return function(el, eventName, fn, capture) {
2442                     el.attachEvent("on" + eventName, fn);
2443                 };
2444             } else {
2445                 return function() {
2446                 };
2447             }
2448         }(),
2449
2450
2451         doRemove: function() {
2452             if (window.removeEventListener) {
2453                 return function (el, eventName, fn, capture) {
2454                     el.removeEventListener(eventName, fn, (capture));
2455                 };
2456             } else if (window.detachEvent) {
2457                 return function (el, eventName, fn) {
2458                     el.detachEvent("on" + eventName, fn);
2459                 };
2460             } else {
2461                 return function() {
2462                 };
2463             }
2464         }()
2465     };
2466     
2467 }();
2468 (function() {     
2469    
2470     var E = Roo.lib.Event;
2471     E.on = E.addListener;
2472     E.un = E.removeListener;
2473
2474     if (document && document.body) {
2475         E._load();
2476     } else {
2477         E.doAdd(window, "load", E._load);
2478     }
2479     E.doAdd(window, "unload", E._unload);
2480     E._tryPreloadAttach();
2481 })();
2482
2483 /*
2484  * Portions of this file are based on pieces of Yahoo User Interface Library
2485  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2486  * YUI licensed under the BSD License:
2487  * http://developer.yahoo.net/yui/license.txt
2488  * <script type="text/javascript">
2489  *
2490  */
2491
2492 (function() {
2493     /**
2494      * @class Roo.lib.Ajax
2495      *
2496      */
2497     Roo.lib.Ajax = {
2498         /**
2499          * @static 
2500          */
2501         request : function(method, uri, cb, data, options) {
2502             if(options){
2503                 var hs = options.headers;
2504                 if(hs){
2505                     for(var h in hs){
2506                         if(hs.hasOwnProperty(h)){
2507                             this.initHeader(h, hs[h], false);
2508                         }
2509                     }
2510                 }
2511                 if(options.xmlData){
2512                     this.initHeader('Content-Type', 'text/xml', false);
2513                     method = 'POST';
2514                     data = options.xmlData;
2515                 }
2516             }
2517
2518             return this.asyncRequest(method, uri, cb, data);
2519         },
2520
2521         serializeForm : function(form) {
2522             if(typeof form == 'string') {
2523                 form = (document.getElementById(form) || document.forms[form]);
2524             }
2525
2526             var el, name, val, disabled, data = '', hasSubmit = false;
2527             for (var i = 0; i < form.elements.length; i++) {
2528                 el = form.elements[i];
2529                 disabled = form.elements[i].disabled;
2530                 name = form.elements[i].name;
2531                 val = form.elements[i].value;
2532
2533                 if (!disabled && name){
2534                     switch (el.type)
2535                             {
2536                         case 'select-one':
2537                         case 'select-multiple':
2538                             for (var j = 0; j < el.options.length; j++) {
2539                                 if (el.options[j].selected) {
2540                                     if (Roo.isIE) {
2541                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2542                                     }
2543                                     else {
2544                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2545                                     }
2546                                 }
2547                             }
2548                             break;
2549                         case 'radio':
2550                         case 'checkbox':
2551                             if (el.checked) {
2552                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2553                             }
2554                             break;
2555                         case 'file':
2556
2557                         case undefined:
2558
2559                         case 'reset':
2560
2561                         case 'button':
2562
2563                             break;
2564                         case 'submit':
2565                             if(hasSubmit == false) {
2566                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2567                                 hasSubmit = true;
2568                             }
2569                             break;
2570                         default:
2571                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2572                             break;
2573                     }
2574                 }
2575             }
2576             data = data.substr(0, data.length - 1);
2577             return data;
2578         },
2579
2580         headers:{},
2581
2582         hasHeaders:false,
2583
2584         useDefaultHeader:true,
2585
2586         defaultPostHeader:'application/x-www-form-urlencoded',
2587
2588         useDefaultXhrHeader:true,
2589
2590         defaultXhrHeader:'XMLHttpRequest',
2591
2592         hasDefaultHeaders:true,
2593
2594         defaultHeaders:{},
2595
2596         poll:{},
2597
2598         timeout:{},
2599
2600         pollInterval:50,
2601
2602         transactionId:0,
2603
2604         setProgId:function(id)
2605         {
2606             this.activeX.unshift(id);
2607         },
2608
2609         setDefaultPostHeader:function(b)
2610         {
2611             this.useDefaultHeader = b;
2612         },
2613
2614         setDefaultXhrHeader:function(b)
2615         {
2616             this.useDefaultXhrHeader = b;
2617         },
2618
2619         setPollingInterval:function(i)
2620         {
2621             if (typeof i == 'number' && isFinite(i)) {
2622                 this.pollInterval = i;
2623             }
2624         },
2625
2626         createXhrObject:function(transactionId)
2627         {
2628             var obj,http;
2629             try
2630             {
2631
2632                 http = new XMLHttpRequest();
2633
2634                 obj = { conn:http, tId:transactionId };
2635             }
2636             catch(e)
2637             {
2638                 for (var i = 0; i < this.activeX.length; ++i) {
2639                     try
2640                     {
2641
2642                         http = new ActiveXObject(this.activeX[i]);
2643
2644                         obj = { conn:http, tId:transactionId };
2645                         break;
2646                     }
2647                     catch(e) {
2648                     }
2649                 }
2650             }
2651             finally
2652             {
2653                 return obj;
2654             }
2655         },
2656
2657         getConnectionObject:function()
2658         {
2659             var o;
2660             var tId = this.transactionId;
2661
2662             try
2663             {
2664                 o = this.createXhrObject(tId);
2665                 if (o) {
2666                     this.transactionId++;
2667                 }
2668             }
2669             catch(e) {
2670             }
2671             finally
2672             {
2673                 return o;
2674             }
2675         },
2676
2677         asyncRequest:function(method, uri, callback, postData)
2678         {
2679             var o = this.getConnectionObject();
2680
2681             if (!o) {
2682                 return null;
2683             }
2684             else {
2685                 o.conn.open(method, uri, true);
2686
2687                 if (this.useDefaultXhrHeader) {
2688                     if (!this.defaultHeaders['X-Requested-With']) {
2689                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2690                     }
2691                 }
2692
2693                 if(postData && this.useDefaultHeader){
2694                     this.initHeader('Content-Type', this.defaultPostHeader);
2695                 }
2696
2697                  if (this.hasDefaultHeaders || this.hasHeaders) {
2698                     this.setHeader(o);
2699                 }
2700
2701                 this.handleReadyState(o, callback);
2702                 o.conn.send(postData || null);
2703
2704                 return o;
2705             }
2706         },
2707
2708         handleReadyState:function(o, callback)
2709         {
2710             var oConn = this;
2711
2712             if (callback && callback.timeout) {
2713                 
2714                 this.timeout[o.tId] = window.setTimeout(function() {
2715                     oConn.abort(o, callback, true);
2716                 }, callback.timeout);
2717             }
2718
2719             this.poll[o.tId] = window.setInterval(
2720                     function() {
2721                         if (o.conn && o.conn.readyState == 4) {
2722                             window.clearInterval(oConn.poll[o.tId]);
2723                             delete oConn.poll[o.tId];
2724
2725                             if(callback && callback.timeout) {
2726                                 window.clearTimeout(oConn.timeout[o.tId]);
2727                                 delete oConn.timeout[o.tId];
2728                             }
2729
2730                             oConn.handleTransactionResponse(o, callback);
2731                         }
2732                     }
2733                     , this.pollInterval);
2734         },
2735
2736         handleTransactionResponse:function(o, callback, isAbort)
2737         {
2738
2739             if (!callback) {
2740                 this.releaseObject(o);
2741                 return;
2742             }
2743
2744             var httpStatus, responseObject;
2745
2746             try
2747             {
2748                 if (o.conn.status !== undefined && o.conn.status != 0) {
2749                     httpStatus = o.conn.status;
2750                 }
2751                 else {
2752                     httpStatus = 13030;
2753                 }
2754             }
2755             catch(e) {
2756
2757
2758                 httpStatus = 13030;
2759             }
2760
2761             if (httpStatus >= 200 && httpStatus < 300) {
2762                 responseObject = this.createResponseObject(o, callback.argument);
2763                 if (callback.success) {
2764                     if (!callback.scope) {
2765                         callback.success(responseObject);
2766                     }
2767                     else {
2768
2769
2770                         callback.success.apply(callback.scope, [responseObject]);
2771                     }
2772                 }
2773             }
2774             else {
2775                 switch (httpStatus) {
2776
2777                     case 12002:
2778                     case 12029:
2779                     case 12030:
2780                     case 12031:
2781                     case 12152:
2782                     case 13030:
2783                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2784                         if (callback.failure) {
2785                             if (!callback.scope) {
2786                                 callback.failure(responseObject);
2787                             }
2788                             else {
2789                                 callback.failure.apply(callback.scope, [responseObject]);
2790                             }
2791                         }
2792                         break;
2793                     default:
2794                         responseObject = this.createResponseObject(o, callback.argument);
2795                         if (callback.failure) {
2796                             if (!callback.scope) {
2797                                 callback.failure(responseObject);
2798                             }
2799                             else {
2800                                 callback.failure.apply(callback.scope, [responseObject]);
2801                             }
2802                         }
2803                 }
2804             }
2805
2806             this.releaseObject(o);
2807             responseObject = null;
2808         },
2809
2810         createResponseObject:function(o, callbackArg)
2811         {
2812             var obj = {};
2813             var headerObj = {};
2814
2815             try
2816             {
2817                 var headerStr = o.conn.getAllResponseHeaders();
2818                 var header = headerStr.split('\n');
2819                 for (var i = 0; i < header.length; i++) {
2820                     var delimitPos = header[i].indexOf(':');
2821                     if (delimitPos != -1) {
2822                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2823                     }
2824                 }
2825             }
2826             catch(e) {
2827             }
2828
2829             obj.tId = o.tId;
2830             obj.status = o.conn.status;
2831             obj.statusText = o.conn.statusText;
2832             obj.getResponseHeader = headerObj;
2833             obj.getAllResponseHeaders = headerStr;
2834             obj.responseText = o.conn.responseText;
2835             obj.responseXML = o.conn.responseXML;
2836
2837             if (typeof callbackArg !== undefined) {
2838                 obj.argument = callbackArg;
2839             }
2840
2841             return obj;
2842         },
2843
2844         createExceptionObject:function(tId, callbackArg, isAbort)
2845         {
2846             var COMM_CODE = 0;
2847             var COMM_ERROR = 'communication failure';
2848             var ABORT_CODE = -1;
2849             var ABORT_ERROR = 'transaction aborted';
2850
2851             var obj = {};
2852
2853             obj.tId = tId;
2854             if (isAbort) {
2855                 obj.status = ABORT_CODE;
2856                 obj.statusText = ABORT_ERROR;
2857             }
2858             else {
2859                 obj.status = COMM_CODE;
2860                 obj.statusText = COMM_ERROR;
2861             }
2862
2863             if (callbackArg) {
2864                 obj.argument = callbackArg;
2865             }
2866
2867             return obj;
2868         },
2869
2870         initHeader:function(label, value, isDefault)
2871         {
2872             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2873
2874             if (headerObj[label] === undefined) {
2875                 headerObj[label] = value;
2876             }
2877             else {
2878
2879
2880                 headerObj[label] = value + "," + headerObj[label];
2881             }
2882
2883             if (isDefault) {
2884                 this.hasDefaultHeaders = true;
2885             }
2886             else {
2887                 this.hasHeaders = true;
2888             }
2889         },
2890
2891
2892         setHeader:function(o)
2893         {
2894             if (this.hasDefaultHeaders) {
2895                 for (var prop in this.defaultHeaders) {
2896                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2897                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2898                     }
2899                 }
2900             }
2901
2902             if (this.hasHeaders) {
2903                 for (var prop in this.headers) {
2904                     if (this.headers.hasOwnProperty(prop)) {
2905                         o.conn.setRequestHeader(prop, this.headers[prop]);
2906                     }
2907                 }
2908                 this.headers = {};
2909                 this.hasHeaders = false;
2910             }
2911         },
2912
2913         resetDefaultHeaders:function() {
2914             delete this.defaultHeaders;
2915             this.defaultHeaders = {};
2916             this.hasDefaultHeaders = false;
2917         },
2918
2919         abort:function(o, callback, isTimeout)
2920         {
2921             if(this.isCallInProgress(o)) {
2922                 o.conn.abort();
2923                 window.clearInterval(this.poll[o.tId]);
2924                 delete this.poll[o.tId];
2925                 if (isTimeout) {
2926                     delete this.timeout[o.tId];
2927                 }
2928
2929                 this.handleTransactionResponse(o, callback, true);
2930
2931                 return true;
2932             }
2933             else {
2934                 return false;
2935             }
2936         },
2937
2938
2939         isCallInProgress:function(o)
2940         {
2941             if (o && o.conn) {
2942                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2943             }
2944             else {
2945
2946                 return false;
2947             }
2948         },
2949
2950
2951         releaseObject:function(o)
2952         {
2953
2954             o.conn = null;
2955
2956             o = null;
2957         },
2958
2959         activeX:[
2960         'MSXML2.XMLHTTP.3.0',
2961         'MSXML2.XMLHTTP',
2962         'Microsoft.XMLHTTP'
2963         ]
2964
2965
2966     };
2967 })();/*
2968  * Portions of this file are based on pieces of Yahoo User Interface Library
2969  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2970  * YUI licensed under the BSD License:
2971  * http://developer.yahoo.net/yui/license.txt
2972  * <script type="text/javascript">
2973  *
2974  */
2975
2976 Roo.lib.Region = function(t, r, b, l) {
2977     this.top = t;
2978     this[1] = t;
2979     this.right = r;
2980     this.bottom = b;
2981     this.left = l;
2982     this[0] = l;
2983 };
2984
2985
2986 Roo.lib.Region.prototype = {
2987     contains : function(region) {
2988         return ( region.left >= this.left &&
2989                  region.right <= this.right &&
2990                  region.top >= this.top &&
2991                  region.bottom <= this.bottom    );
2992
2993     },
2994
2995     getArea : function() {
2996         return ( (this.bottom - this.top) * (this.right - this.left) );
2997     },
2998
2999     intersect : function(region) {
3000         var t = Math.max(this.top, region.top);
3001         var r = Math.min(this.right, region.right);
3002         var b = Math.min(this.bottom, region.bottom);
3003         var l = Math.max(this.left, region.left);
3004
3005         if (b >= t && r >= l) {
3006             return new Roo.lib.Region(t, r, b, l);
3007         } else {
3008             return null;
3009         }
3010     },
3011     union : function(region) {
3012         var t = Math.min(this.top, region.top);
3013         var r = Math.max(this.right, region.right);
3014         var b = Math.max(this.bottom, region.bottom);
3015         var l = Math.min(this.left, region.left);
3016
3017         return new Roo.lib.Region(t, r, b, l);
3018     },
3019
3020     adjust : function(t, l, b, r) {
3021         this.top += t;
3022         this.left += l;
3023         this.right += r;
3024         this.bottom += b;
3025         return this;
3026     }
3027 };
3028
3029 Roo.lib.Region.getRegion = function(el) {
3030     var p = Roo.lib.Dom.getXY(el);
3031
3032     var t = p[1];
3033     var r = p[0] + el.offsetWidth;
3034     var b = p[1] + el.offsetHeight;
3035     var l = p[0];
3036
3037     return new Roo.lib.Region(t, r, b, l);
3038 };
3039 /*
3040  * Portions of this file are based on pieces of Yahoo User Interface Library
3041  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3042  * YUI licensed under the BSD License:
3043  * http://developer.yahoo.net/yui/license.txt
3044  * <script type="text/javascript">
3045  *
3046  */
3047 //@@dep Roo.lib.Region
3048
3049
3050 Roo.lib.Point = function(x, y) {
3051     if (x instanceof Array) {
3052         y = x[1];
3053         x = x[0];
3054     }
3055     this.x = this.right = this.left = this[0] = x;
3056     this.y = this.top = this.bottom = this[1] = y;
3057 };
3058
3059 Roo.lib.Point.prototype = new Roo.lib.Region();
3060 /*
3061  * Portions of this file are based on pieces of Yahoo User Interface Library
3062  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3063  * YUI licensed under the BSD License:
3064  * http://developer.yahoo.net/yui/license.txt
3065  * <script type="text/javascript">
3066  *
3067  */
3068  
3069 (function() {   
3070
3071     Roo.lib.Anim = {
3072         scroll : function(el, args, duration, easing, cb, scope) {
3073             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3074         },
3075
3076         motion : function(el, args, duration, easing, cb, scope) {
3077             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3078         },
3079
3080         color : function(el, args, duration, easing, cb, scope) {
3081             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3082         },
3083
3084         run : function(el, args, duration, easing, cb, scope, type) {
3085             type = type || Roo.lib.AnimBase;
3086             if (typeof easing == "string") {
3087                 easing = Roo.lib.Easing[easing];
3088             }
3089             var anim = new type(el, args, duration, easing);
3090             anim.animateX(function() {
3091                 Roo.callback(cb, scope);
3092             });
3093             return anim;
3094         }
3095     };
3096 })();/*
3097  * Portions of this file are based on pieces of Yahoo User Interface Library
3098  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3099  * YUI licensed under the BSD License:
3100  * http://developer.yahoo.net/yui/license.txt
3101  * <script type="text/javascript">
3102  *
3103  */
3104
3105 (function() {    
3106     var libFlyweight;
3107     
3108     function fly(el) {
3109         if (!libFlyweight) {
3110             libFlyweight = new Roo.Element.Flyweight();
3111         }
3112         libFlyweight.dom = el;
3113         return libFlyweight;
3114     }
3115
3116     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3117     
3118    
3119     
3120     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3121         if (el) {
3122             this.init(el, attributes, duration, method);
3123         }
3124     };
3125
3126     Roo.lib.AnimBase.fly = fly;
3127     
3128     
3129     
3130     Roo.lib.AnimBase.prototype = {
3131
3132         toString: function() {
3133             var el = this.getEl();
3134             var id = el.id || el.tagName;
3135             return ("Anim " + id);
3136         },
3137
3138         patterns: {
3139             noNegatives:        /width|height|opacity|padding/i,
3140             offsetAttribute:  /^((width|height)|(top|left))$/,
3141             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3142             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3143         },
3144
3145
3146         doMethod: function(attr, start, end) {
3147             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3148         },
3149
3150
3151         setAttribute: function(attr, val, unit) {
3152             if (this.patterns.noNegatives.test(attr)) {
3153                 val = (val > 0) ? val : 0;
3154             }
3155
3156             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3157         },
3158
3159
3160         getAttribute: function(attr) {
3161             var el = this.getEl();
3162             var val = fly(el).getStyle(attr);
3163
3164             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3165                 return parseFloat(val);
3166             }
3167
3168             var a = this.patterns.offsetAttribute.exec(attr) || [];
3169             var pos = !!( a[3] );
3170             var box = !!( a[2] );
3171
3172
3173             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3174                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3175             } else {
3176                 val = 0;
3177             }
3178
3179             return val;
3180         },
3181
3182
3183         getDefaultUnit: function(attr) {
3184             if (this.patterns.defaultUnit.test(attr)) {
3185                 return 'px';
3186             }
3187
3188             return '';
3189         },
3190
3191         animateX : function(callback, scope) {
3192             var f = function() {
3193                 this.onComplete.removeListener(f);
3194                 if (typeof callback == "function") {
3195                     callback.call(scope || this, this);
3196                 }
3197             };
3198             this.onComplete.addListener(f, this);
3199             this.animate();
3200         },
3201
3202
3203         setRuntimeAttribute: function(attr) {
3204             var start;
3205             var end;
3206             var attributes = this.attributes;
3207
3208             this.runtimeAttributes[attr] = {};
3209
3210             var isset = function(prop) {
3211                 return (typeof prop !== 'undefined');
3212             };
3213
3214             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3215                 return false;
3216             }
3217
3218             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3219
3220
3221             if (isset(attributes[attr]['to'])) {
3222                 end = attributes[attr]['to'];
3223             } else if (isset(attributes[attr]['by'])) {
3224                 if (start.constructor == Array) {
3225                     end = [];
3226                     for (var i = 0, len = start.length; i < len; ++i) {
3227                         end[i] = start[i] + attributes[attr]['by'][i];
3228                     }
3229                 } else {
3230                     end = start + attributes[attr]['by'];
3231                 }
3232             }
3233
3234             this.runtimeAttributes[attr].start = start;
3235             this.runtimeAttributes[attr].end = end;
3236
3237
3238             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3239         },
3240
3241
3242         init: function(el, attributes, duration, method) {
3243
3244             var isAnimated = false;
3245
3246
3247             var startTime = null;
3248
3249
3250             var actualFrames = 0;
3251
3252
3253             el = Roo.getDom(el);
3254
3255
3256             this.attributes = attributes || {};
3257
3258
3259             this.duration = duration || 1;
3260
3261
3262             this.method = method || Roo.lib.Easing.easeNone;
3263
3264
3265             this.useSeconds = true;
3266
3267
3268             this.currentFrame = 0;
3269
3270
3271             this.totalFrames = Roo.lib.AnimMgr.fps;
3272
3273
3274             this.getEl = function() {
3275                 return el;
3276             };
3277
3278
3279             this.isAnimated = function() {
3280                 return isAnimated;
3281             };
3282
3283
3284             this.getStartTime = function() {
3285                 return startTime;
3286             };
3287
3288             this.runtimeAttributes = {};
3289
3290
3291             this.animate = function() {
3292                 if (this.isAnimated()) {
3293                     return false;
3294                 }
3295
3296                 this.currentFrame = 0;
3297
3298                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3299
3300                 Roo.lib.AnimMgr.registerElement(this);
3301             };
3302
3303
3304             this.stop = function(finish) {
3305                 if (finish) {
3306                     this.currentFrame = this.totalFrames;
3307                     this._onTween.fire();
3308                 }
3309                 Roo.lib.AnimMgr.stop(this);
3310             };
3311
3312             var onStart = function() {
3313                 this.onStart.fire();
3314
3315                 this.runtimeAttributes = {};
3316                 for (var attr in this.attributes) {
3317                     this.setRuntimeAttribute(attr);
3318                 }
3319
3320                 isAnimated = true;
3321                 actualFrames = 0;
3322                 startTime = new Date();
3323             };
3324
3325
3326             var onTween = function() {
3327                 var data = {
3328                     duration: new Date() - this.getStartTime(),
3329                     currentFrame: this.currentFrame
3330                 };
3331
3332                 data.toString = function() {
3333                     return (
3334                             'duration: ' + data.duration +
3335                             ', currentFrame: ' + data.currentFrame
3336                             );
3337                 };
3338
3339                 this.onTween.fire(data);
3340
3341                 var runtimeAttributes = this.runtimeAttributes;
3342
3343                 for (var attr in runtimeAttributes) {
3344                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3345                 }
3346
3347                 actualFrames += 1;
3348             };
3349
3350             var onComplete = function() {
3351                 var actual_duration = (new Date() - startTime) / 1000 ;
3352
3353                 var data = {
3354                     duration: actual_duration,
3355                     frames: actualFrames,
3356                     fps: actualFrames / actual_duration
3357                 };
3358
3359                 data.toString = function() {
3360                     return (
3361                             'duration: ' + data.duration +
3362                             ', frames: ' + data.frames +
3363                             ', fps: ' + data.fps
3364                             );
3365                 };
3366
3367                 isAnimated = false;
3368                 actualFrames = 0;
3369                 this.onComplete.fire(data);
3370             };
3371
3372
3373             this._onStart = new Roo.util.Event(this);
3374             this.onStart = new Roo.util.Event(this);
3375             this.onTween = new Roo.util.Event(this);
3376             this._onTween = new Roo.util.Event(this);
3377             this.onComplete = new Roo.util.Event(this);
3378             this._onComplete = new Roo.util.Event(this);
3379             this._onStart.addListener(onStart);
3380             this._onTween.addListener(onTween);
3381             this._onComplete.addListener(onComplete);
3382         }
3383     };
3384 })();
3385 /*
3386  * Portions of this file are based on pieces of Yahoo User Interface Library
3387  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3388  * YUI licensed under the BSD License:
3389  * http://developer.yahoo.net/yui/license.txt
3390  * <script type="text/javascript">
3391  *
3392  */
3393
3394 Roo.lib.AnimMgr = new function() {
3395
3396         var thread = null;
3397
3398
3399         var queue = [];
3400
3401
3402         var tweenCount = 0;
3403
3404
3405         this.fps = 1000;
3406
3407
3408         this.delay = 1;
3409
3410
3411         this.registerElement = function(tween) {
3412             queue[queue.length] = tween;
3413             tweenCount += 1;
3414             tween._onStart.fire();
3415             this.start();
3416         };
3417
3418
3419         this.unRegister = function(tween, index) {
3420             tween._onComplete.fire();
3421             index = index || getIndex(tween);
3422             if (index != -1) {
3423                 queue.splice(index, 1);
3424             }
3425
3426             tweenCount -= 1;
3427             if (tweenCount <= 0) {
3428                 this.stop();
3429             }
3430         };
3431
3432
3433         this.start = function() {
3434             if (thread === null) {
3435                 thread = setInterval(this.run, this.delay);
3436             }
3437         };
3438
3439
3440         this.stop = function(tween) {
3441             if (!tween) {
3442                 clearInterval(thread);
3443
3444                 for (var i = 0, len = queue.length; i < len; ++i) {
3445                     if (queue[0].isAnimated()) {
3446                         this.unRegister(queue[0], 0);
3447                     }
3448                 }
3449
3450                 queue = [];
3451                 thread = null;
3452                 tweenCount = 0;
3453             }
3454             else {
3455                 this.unRegister(tween);
3456             }
3457         };
3458
3459
3460         this.run = function() {
3461             for (var i = 0, len = queue.length; i < len; ++i) {
3462                 var tween = queue[i];
3463                 if (!tween || !tween.isAnimated()) {
3464                     continue;
3465                 }
3466
3467                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3468                 {
3469                     tween.currentFrame += 1;
3470
3471                     if (tween.useSeconds) {
3472                         correctFrame(tween);
3473                     }
3474                     tween._onTween.fire();
3475                 }
3476                 else {
3477                     Roo.lib.AnimMgr.stop(tween, i);
3478                 }
3479             }
3480         };
3481
3482         var getIndex = function(anim) {
3483             for (var i = 0, len = queue.length; i < len; ++i) {
3484                 if (queue[i] == anim) {
3485                     return i;
3486                 }
3487             }
3488             return -1;
3489         };
3490
3491
3492         var correctFrame = function(tween) {
3493             var frames = tween.totalFrames;
3494             var frame = tween.currentFrame;
3495             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3496             var elapsed = (new Date() - tween.getStartTime());
3497             var tweak = 0;
3498
3499             if (elapsed < tween.duration * 1000) {
3500                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3501             } else {
3502                 tweak = frames - (frame + 1);
3503             }
3504             if (tweak > 0 && isFinite(tweak)) {
3505                 if (tween.currentFrame + tweak >= frames) {
3506                     tweak = frames - (frame + 1);
3507                 }
3508
3509                 tween.currentFrame += tweak;
3510             }
3511         };
3512     };/*
3513  * Portions of this file are based on pieces of Yahoo User Interface Library
3514  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3515  * YUI licensed under the BSD License:
3516  * http://developer.yahoo.net/yui/license.txt
3517  * <script type="text/javascript">
3518  *
3519  */
3520 Roo.lib.Bezier = new function() {
3521
3522         this.getPosition = function(points, t) {
3523             var n = points.length;
3524             var tmp = [];
3525
3526             for (var i = 0; i < n; ++i) {
3527                 tmp[i] = [points[i][0], points[i][1]];
3528             }
3529
3530             for (var j = 1; j < n; ++j) {
3531                 for (i = 0; i < n - j; ++i) {
3532                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3533                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3534                 }
3535             }
3536
3537             return [ tmp[0][0], tmp[0][1] ];
3538
3539         };
3540     };/*
3541  * Portions of this file are based on pieces of Yahoo User Interface Library
3542  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3543  * YUI licensed under the BSD License:
3544  * http://developer.yahoo.net/yui/license.txt
3545  * <script type="text/javascript">
3546  *
3547  */
3548 (function() {
3549
3550     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3551         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3552     };
3553
3554     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3555
3556     var fly = Roo.lib.AnimBase.fly;
3557     var Y = Roo.lib;
3558     var superclass = Y.ColorAnim.superclass;
3559     var proto = Y.ColorAnim.prototype;
3560
3561     proto.toString = function() {
3562         var el = this.getEl();
3563         var id = el.id || el.tagName;
3564         return ("ColorAnim " + id);
3565     };
3566
3567     proto.patterns.color = /color$/i;
3568     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3569     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3570     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3571     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3572
3573
3574     proto.parseColor = function(s) {
3575         if (s.length == 3) {
3576             return s;
3577         }
3578
3579         var c = this.patterns.hex.exec(s);
3580         if (c && c.length == 4) {
3581             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3582         }
3583
3584         c = this.patterns.rgb.exec(s);
3585         if (c && c.length == 4) {
3586             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3587         }
3588
3589         c = this.patterns.hex3.exec(s);
3590         if (c && c.length == 4) {
3591             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3592         }
3593
3594         return null;
3595     };
3596     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3597     proto.getAttribute = function(attr) {
3598         var el = this.getEl();
3599         if (this.patterns.color.test(attr)) {
3600             var val = fly(el).getStyle(attr);
3601
3602             if (this.patterns.transparent.test(val)) {
3603                 var parent = el.parentNode;
3604                 val = fly(parent).getStyle(attr);
3605
3606                 while (parent && this.patterns.transparent.test(val)) {
3607                     parent = parent.parentNode;
3608                     val = fly(parent).getStyle(attr);
3609                     if (parent.tagName.toUpperCase() == 'HTML') {
3610                         val = '#fff';
3611                     }
3612                 }
3613             }
3614         } else {
3615             val = superclass.getAttribute.call(this, attr);
3616         }
3617
3618         return val;
3619     };
3620     proto.getAttribute = function(attr) {
3621         var el = this.getEl();
3622         if (this.patterns.color.test(attr)) {
3623             var val = fly(el).getStyle(attr);
3624
3625             if (this.patterns.transparent.test(val)) {
3626                 var parent = el.parentNode;
3627                 val = fly(parent).getStyle(attr);
3628
3629                 while (parent && this.patterns.transparent.test(val)) {
3630                     parent = parent.parentNode;
3631                     val = fly(parent).getStyle(attr);
3632                     if (parent.tagName.toUpperCase() == 'HTML') {
3633                         val = '#fff';
3634                     }
3635                 }
3636             }
3637         } else {
3638             val = superclass.getAttribute.call(this, attr);
3639         }
3640
3641         return val;
3642     };
3643
3644     proto.doMethod = function(attr, start, end) {
3645         var val;
3646
3647         if (this.patterns.color.test(attr)) {
3648             val = [];
3649             for (var i = 0, len = start.length; i < len; ++i) {
3650                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3651             }
3652
3653             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3654         }
3655         else {
3656             val = superclass.doMethod.call(this, attr, start, end);
3657         }
3658
3659         return val;
3660     };
3661
3662     proto.setRuntimeAttribute = function(attr) {
3663         superclass.setRuntimeAttribute.call(this, attr);
3664
3665         if (this.patterns.color.test(attr)) {
3666             var attributes = this.attributes;
3667             var start = this.parseColor(this.runtimeAttributes[attr].start);
3668             var end = this.parseColor(this.runtimeAttributes[attr].end);
3669
3670             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3671                 end = this.parseColor(attributes[attr].by);
3672
3673                 for (var i = 0, len = start.length; i < len; ++i) {
3674                     end[i] = start[i] + end[i];
3675                 }
3676             }
3677
3678             this.runtimeAttributes[attr].start = start;
3679             this.runtimeAttributes[attr].end = end;
3680         }
3681     };
3682 })();
3683
3684 /*
3685  * Portions of this file are based on pieces of Yahoo User Interface Library
3686  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3687  * YUI licensed under the BSD License:
3688  * http://developer.yahoo.net/yui/license.txt
3689  * <script type="text/javascript">
3690  *
3691  */
3692 Roo.lib.Easing = {
3693
3694
3695     easeNone: function (t, b, c, d) {
3696         return c * t / d + b;
3697     },
3698
3699
3700     easeIn: function (t, b, c, d) {
3701         return c * (t /= d) * t + b;
3702     },
3703
3704
3705     easeOut: function (t, b, c, d) {
3706         return -c * (t /= d) * (t - 2) + b;
3707     },
3708
3709
3710     easeBoth: function (t, b, c, d) {
3711         if ((t /= d / 2) < 1) {
3712             return c / 2 * t * t + b;
3713         }
3714
3715         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3716     },
3717
3718
3719     easeInStrong: function (t, b, c, d) {
3720         return c * (t /= d) * t * t * t + b;
3721     },
3722
3723
3724     easeOutStrong: function (t, b, c, d) {
3725         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3726     },
3727
3728
3729     easeBothStrong: function (t, b, c, d) {
3730         if ((t /= d / 2) < 1) {
3731             return c / 2 * t * t * t * t + b;
3732         }
3733
3734         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3735     },
3736
3737
3738
3739     elasticIn: function (t, b, c, d, a, p) {
3740         if (t == 0) {
3741             return b;
3742         }
3743         if ((t /= d) == 1) {
3744             return b + c;
3745         }
3746         if (!p) {
3747             p = d * .3;
3748         }
3749
3750         if (!a || a < Math.abs(c)) {
3751             a = c;
3752             var s = p / 4;
3753         }
3754         else {
3755             var s = p / (2 * Math.PI) * Math.asin(c / a);
3756         }
3757
3758         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3759     },
3760
3761
3762     elasticOut: function (t, b, c, d, a, p) {
3763         if (t == 0) {
3764             return b;
3765         }
3766         if ((t /= d) == 1) {
3767             return b + c;
3768         }
3769         if (!p) {
3770             p = d * .3;
3771         }
3772
3773         if (!a || a < Math.abs(c)) {
3774             a = c;
3775             var s = p / 4;
3776         }
3777         else {
3778             var s = p / (2 * Math.PI) * Math.asin(c / a);
3779         }
3780
3781         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3782     },
3783
3784
3785     elasticBoth: function (t, b, c, d, a, p) {
3786         if (t == 0) {
3787             return b;
3788         }
3789
3790         if ((t /= d / 2) == 2) {
3791             return b + c;
3792         }
3793
3794         if (!p) {
3795             p = d * (.3 * 1.5);
3796         }
3797
3798         if (!a || a < Math.abs(c)) {
3799             a = c;
3800             var s = p / 4;
3801         }
3802         else {
3803             var s = p / (2 * Math.PI) * Math.asin(c / a);
3804         }
3805
3806         if (t < 1) {
3807             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3808                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3809         }
3810         return a * Math.pow(2, -10 * (t -= 1)) *
3811                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3812     },
3813
3814
3815
3816     backIn: function (t, b, c, d, s) {
3817         if (typeof s == 'undefined') {
3818             s = 1.70158;
3819         }
3820         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3821     },
3822
3823
3824     backOut: function (t, b, c, d, s) {
3825         if (typeof s == 'undefined') {
3826             s = 1.70158;
3827         }
3828         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3829     },
3830
3831
3832     backBoth: function (t, b, c, d, s) {
3833         if (typeof s == 'undefined') {
3834             s = 1.70158;
3835         }
3836
3837         if ((t /= d / 2 ) < 1) {
3838             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3839         }
3840         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3841     },
3842
3843
3844     bounceIn: function (t, b, c, d) {
3845         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3846     },
3847
3848
3849     bounceOut: function (t, b, c, d) {
3850         if ((t /= d) < (1 / 2.75)) {
3851             return c * (7.5625 * t * t) + b;
3852         } else if (t < (2 / 2.75)) {
3853             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3854         } else if (t < (2.5 / 2.75)) {
3855             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3856         }
3857         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3858     },
3859
3860
3861     bounceBoth: function (t, b, c, d) {
3862         if (t < d / 2) {
3863             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3864         }
3865         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3866     }
3867 };/*
3868  * Portions of this file are based on pieces of Yahoo User Interface Library
3869  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3870  * YUI licensed under the BSD License:
3871  * http://developer.yahoo.net/yui/license.txt
3872  * <script type="text/javascript">
3873  *
3874  */
3875     (function() {
3876         Roo.lib.Motion = function(el, attributes, duration, method) {
3877             if (el) {
3878                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3879             }
3880         };
3881
3882         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3883
3884
3885         var Y = Roo.lib;
3886         var superclass = Y.Motion.superclass;
3887         var proto = Y.Motion.prototype;
3888
3889         proto.toString = function() {
3890             var el = this.getEl();
3891             var id = el.id || el.tagName;
3892             return ("Motion " + id);
3893         };
3894
3895         proto.patterns.points = /^points$/i;
3896
3897         proto.setAttribute = function(attr, val, unit) {
3898             if (this.patterns.points.test(attr)) {
3899                 unit = unit || 'px';
3900                 superclass.setAttribute.call(this, 'left', val[0], unit);
3901                 superclass.setAttribute.call(this, 'top', val[1], unit);
3902             } else {
3903                 superclass.setAttribute.call(this, attr, val, unit);
3904             }
3905         };
3906
3907         proto.getAttribute = function(attr) {
3908             if (this.patterns.points.test(attr)) {
3909                 var val = [
3910                         superclass.getAttribute.call(this, 'left'),
3911                         superclass.getAttribute.call(this, 'top')
3912                         ];
3913             } else {
3914                 val = superclass.getAttribute.call(this, attr);
3915             }
3916
3917             return val;
3918         };
3919
3920         proto.doMethod = function(attr, start, end) {
3921             var val = null;
3922
3923             if (this.patterns.points.test(attr)) {
3924                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3925                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3926             } else {
3927                 val = superclass.doMethod.call(this, attr, start, end);
3928             }
3929             return val;
3930         };
3931
3932         proto.setRuntimeAttribute = function(attr) {
3933             if (this.patterns.points.test(attr)) {
3934                 var el = this.getEl();
3935                 var attributes = this.attributes;
3936                 var start;
3937                 var control = attributes['points']['control'] || [];
3938                 var end;
3939                 var i, len;
3940
3941                 if (control.length > 0 && !(control[0] instanceof Array)) {
3942                     control = [control];
3943                 } else {
3944                     var tmp = [];
3945                     for (i = 0,len = control.length; i < len; ++i) {
3946                         tmp[i] = control[i];
3947                     }
3948                     control = tmp;
3949                 }
3950
3951                 Roo.fly(el).position();
3952
3953                 if (isset(attributes['points']['from'])) {
3954                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3955                 }
3956                 else {
3957                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3958                 }
3959
3960                 start = this.getAttribute('points');
3961
3962
3963                 if (isset(attributes['points']['to'])) {
3964                     end = translateValues.call(this, attributes['points']['to'], start);
3965
3966                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3967                     for (i = 0,len = control.length; i < len; ++i) {
3968                         control[i] = translateValues.call(this, control[i], start);
3969                     }
3970
3971
3972                 } else if (isset(attributes['points']['by'])) {
3973                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3974
3975                     for (i = 0,len = control.length; i < len; ++i) {
3976                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3977                     }
3978                 }
3979
3980                 this.runtimeAttributes[attr] = [start];
3981
3982                 if (control.length > 0) {
3983                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3984                 }
3985
3986                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3987             }
3988             else {
3989                 superclass.setRuntimeAttribute.call(this, attr);
3990             }
3991         };
3992
3993         var translateValues = function(val, start) {
3994             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3995             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3996
3997             return val;
3998         };
3999
4000         var isset = function(prop) {
4001             return (typeof prop !== 'undefined');
4002         };
4003     })();
4004 /*
4005  * Portions of this file are based on pieces of Yahoo User Interface Library
4006  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4007  * YUI licensed under the BSD License:
4008  * http://developer.yahoo.net/yui/license.txt
4009  * <script type="text/javascript">
4010  *
4011  */
4012     (function() {
4013         Roo.lib.Scroll = function(el, attributes, duration, method) {
4014             if (el) {
4015                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4016             }
4017         };
4018
4019         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4020
4021
4022         var Y = Roo.lib;
4023         var superclass = Y.Scroll.superclass;
4024         var proto = Y.Scroll.prototype;
4025
4026         proto.toString = function() {
4027             var el = this.getEl();
4028             var id = el.id || el.tagName;
4029             return ("Scroll " + id);
4030         };
4031
4032         proto.doMethod = function(attr, start, end) {
4033             var val = null;
4034
4035             if (attr == 'scroll') {
4036                 val = [
4037                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4038                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4039                         ];
4040
4041             } else {
4042                 val = superclass.doMethod.call(this, attr, start, end);
4043             }
4044             return val;
4045         };
4046
4047         proto.getAttribute = function(attr) {
4048             var val = null;
4049             var el = this.getEl();
4050
4051             if (attr == 'scroll') {
4052                 val = [ el.scrollLeft, el.scrollTop ];
4053             } else {
4054                 val = superclass.getAttribute.call(this, attr);
4055             }
4056
4057             return val;
4058         };
4059
4060         proto.setAttribute = function(attr, val, unit) {
4061             var el = this.getEl();
4062
4063             if (attr == 'scroll') {
4064                 el.scrollLeft = val[0];
4065                 el.scrollTop = val[1];
4066             } else {
4067                 superclass.setAttribute.call(this, attr, val, unit);
4068             }
4069         };
4070     })();
4071 /*
4072  * Based on:
4073  * Ext JS Library 1.1.1
4074  * Copyright(c) 2006-2007, Ext JS, LLC.
4075  *
4076  * Originally Released Under LGPL - original licence link has changed is not relivant.
4077  *
4078  * Fork - LGPL
4079  * <script type="text/javascript">
4080  */
4081
4082
4083 // nasty IE9 hack - what a pile of crap that is..
4084
4085  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4086     Range.prototype.createContextualFragment = function (html) {
4087         var doc = window.document;
4088         var container = doc.createElement("div");
4089         container.innerHTML = html;
4090         var frag = doc.createDocumentFragment(), n;
4091         while ((n = container.firstChild)) {
4092             frag.appendChild(n);
4093         }
4094         return frag;
4095     };
4096 }
4097
4098 /**
4099  * @class Roo.DomHelper
4100  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4101  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4102  * @singleton
4103  */
4104 Roo.DomHelper = function(){
4105     var tempTableEl = null;
4106     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4107     var tableRe = /^table|tbody|tr|td$/i;
4108     var xmlns = {};
4109     // build as innerHTML where available
4110     /** @ignore */
4111     var createHtml = function(o){
4112         if(typeof o == 'string'){
4113             return o;
4114         }
4115         var b = "";
4116         if(!o.tag){
4117             o.tag = "div";
4118         }
4119         b += "<" + o.tag;
4120         for(var attr in o){
4121             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4122             if(attr == "style"){
4123                 var s = o["style"];
4124                 if(typeof s == "function"){
4125                     s = s.call();
4126                 }
4127                 if(typeof s == "string"){
4128                     b += ' style="' + s + '"';
4129                 }else if(typeof s == "object"){
4130                     b += ' style="';
4131                     for(var key in s){
4132                         if(typeof s[key] != "function"){
4133                             b += key + ":" + s[key] + ";";
4134                         }
4135                     }
4136                     b += '"';
4137                 }
4138             }else{
4139                 if(attr == "cls"){
4140                     b += ' class="' + o["cls"] + '"';
4141                 }else if(attr == "htmlFor"){
4142                     b += ' for="' + o["htmlFor"] + '"';
4143                 }else{
4144                     b += " " + attr + '="' + o[attr] + '"';
4145                 }
4146             }
4147         }
4148         if(emptyTags.test(o.tag)){
4149             b += "/>";
4150         }else{
4151             b += ">";
4152             var cn = o.children || o.cn;
4153             if(cn){
4154                 //http://bugs.kde.org/show_bug.cgi?id=71506
4155                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4156                     for(var i = 0, len = cn.length; i < len; i++) {
4157                         b += createHtml(cn[i], b);
4158                     }
4159                 }else{
4160                     b += createHtml(cn, b);
4161                 }
4162             }
4163             if(o.html){
4164                 b += o.html;
4165             }
4166             b += "</" + o.tag + ">";
4167         }
4168         return b;
4169     };
4170
4171     // build as dom
4172     /** @ignore */
4173     var createDom = function(o, parentNode){
4174          
4175         // defininition craeted..
4176         var ns = false;
4177         if (o.ns && o.ns != 'html') {
4178                
4179             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4180                 xmlns[o.ns] = o.xmlns;
4181                 ns = o.xmlns;
4182             }
4183             if (typeof(xmlns[o.ns]) == 'undefined') {
4184                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4185             }
4186             ns = xmlns[o.ns];
4187         }
4188         
4189         
4190         if (typeof(o) == 'string') {
4191             return parentNode.appendChild(document.createTextNode(o));
4192         }
4193         o.tag = o.tag || div;
4194         if (o.ns && Roo.isIE) {
4195             ns = false;
4196             o.tag = o.ns + ':' + o.tag;
4197             
4198         }
4199         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4200         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4201         for(var attr in o){
4202             
4203             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4204                     attr == "style" || typeof o[attr] == "function") continue;
4205                     
4206             if(attr=="cls" && Roo.isIE){
4207                 el.className = o["cls"];
4208             }else{
4209                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4210                 else el[attr] = o[attr];
4211             }
4212         }
4213         Roo.DomHelper.applyStyles(el, o.style);
4214         var cn = o.children || o.cn;
4215         if(cn){
4216             //http://bugs.kde.org/show_bug.cgi?id=71506
4217              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4218                 for(var i = 0, len = cn.length; i < len; i++) {
4219                     createDom(cn[i], el);
4220                 }
4221             }else{
4222                 createDom(cn, el);
4223             }
4224         }
4225         if(o.html){
4226             el.innerHTML = o.html;
4227         }
4228         if(parentNode){
4229            parentNode.appendChild(el);
4230         }
4231         return el;
4232     };
4233
4234     var ieTable = function(depth, s, h, e){
4235         tempTableEl.innerHTML = [s, h, e].join('');
4236         var i = -1, el = tempTableEl;
4237         while(++i < depth){
4238             el = el.firstChild;
4239         }
4240         return el;
4241     };
4242
4243     // kill repeat to save bytes
4244     var ts = '<table>',
4245         te = '</table>',
4246         tbs = ts+'<tbody>',
4247         tbe = '</tbody>'+te,
4248         trs = tbs + '<tr>',
4249         tre = '</tr>'+tbe;
4250
4251     /**
4252      * @ignore
4253      * Nasty code for IE's broken table implementation
4254      */
4255     var insertIntoTable = function(tag, where, el, html){
4256         if(!tempTableEl){
4257             tempTableEl = document.createElement('div');
4258         }
4259         var node;
4260         var before = null;
4261         if(tag == 'td'){
4262             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4263                 return;
4264             }
4265             if(where == 'beforebegin'){
4266                 before = el;
4267                 el = el.parentNode;
4268             } else{
4269                 before = el.nextSibling;
4270                 el = el.parentNode;
4271             }
4272             node = ieTable(4, trs, html, tre);
4273         }
4274         else if(tag == 'tr'){
4275             if(where == 'beforebegin'){
4276                 before = el;
4277                 el = el.parentNode;
4278                 node = ieTable(3, tbs, html, tbe);
4279             } else if(where == 'afterend'){
4280                 before = el.nextSibling;
4281                 el = el.parentNode;
4282                 node = ieTable(3, tbs, html, tbe);
4283             } else{ // INTO a TR
4284                 if(where == 'afterbegin'){
4285                     before = el.firstChild;
4286                 }
4287                 node = ieTable(4, trs, html, tre);
4288             }
4289         } else if(tag == 'tbody'){
4290             if(where == 'beforebegin'){
4291                 before = el;
4292                 el = el.parentNode;
4293                 node = ieTable(2, ts, html, te);
4294             } else if(where == 'afterend'){
4295                 before = el.nextSibling;
4296                 el = el.parentNode;
4297                 node = ieTable(2, ts, html, te);
4298             } else{
4299                 if(where == 'afterbegin'){
4300                     before = el.firstChild;
4301                 }
4302                 node = ieTable(3, tbs, html, tbe);
4303             }
4304         } else{ // TABLE
4305             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4306                 return;
4307             }
4308             if(where == 'afterbegin'){
4309                 before = el.firstChild;
4310             }
4311             node = ieTable(2, ts, html, te);
4312         }
4313         el.insertBefore(node, before);
4314         return node;
4315     };
4316
4317     return {
4318     /** True to force the use of DOM instead of html fragments @type Boolean */
4319     useDom : false,
4320
4321     /**
4322      * Returns the markup for the passed Element(s) config
4323      * @param {Object} o The Dom object spec (and children)
4324      * @return {String}
4325      */
4326     markup : function(o){
4327         return createHtml(o);
4328     },
4329
4330     /**
4331      * Applies a style specification to an element
4332      * @param {String/HTMLElement} el The element to apply styles to
4333      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4334      * a function which returns such a specification.
4335      */
4336     applyStyles : function(el, styles){
4337         if(styles){
4338            el = Roo.fly(el);
4339            if(typeof styles == "string"){
4340                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4341                var matches;
4342                while ((matches = re.exec(styles)) != null){
4343                    el.setStyle(matches[1], matches[2]);
4344                }
4345            }else if (typeof styles == "object"){
4346                for (var style in styles){
4347                   el.setStyle(style, styles[style]);
4348                }
4349            }else if (typeof styles == "function"){
4350                 Roo.DomHelper.applyStyles(el, styles.call());
4351            }
4352         }
4353     },
4354
4355     /**
4356      * Inserts an HTML fragment into the Dom
4357      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4358      * @param {HTMLElement} el The context element
4359      * @param {String} html The HTML fragmenet
4360      * @return {HTMLElement} The new node
4361      */
4362     insertHtml : function(where, el, html){
4363         where = where.toLowerCase();
4364         if(el.insertAdjacentHTML){
4365             if(tableRe.test(el.tagName)){
4366                 var rs;
4367                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4368                     return rs;
4369                 }
4370             }
4371             switch(where){
4372                 case "beforebegin":
4373                     el.insertAdjacentHTML('BeforeBegin', html);
4374                     return el.previousSibling;
4375                 case "afterbegin":
4376                     el.insertAdjacentHTML('AfterBegin', html);
4377                     return el.firstChild;
4378                 case "beforeend":
4379                     el.insertAdjacentHTML('BeforeEnd', html);
4380                     return el.lastChild;
4381                 case "afterend":
4382                     el.insertAdjacentHTML('AfterEnd', html);
4383                     return el.nextSibling;
4384             }
4385             throw 'Illegal insertion point -> "' + where + '"';
4386         }
4387         var range = el.ownerDocument.createRange();
4388         var frag;
4389         switch(where){
4390              case "beforebegin":
4391                 range.setStartBefore(el);
4392                 frag = range.createContextualFragment(html);
4393                 el.parentNode.insertBefore(frag, el);
4394                 return el.previousSibling;
4395              case "afterbegin":
4396                 if(el.firstChild){
4397                     range.setStartBefore(el.firstChild);
4398                     frag = range.createContextualFragment(html);
4399                     el.insertBefore(frag, el.firstChild);
4400                     return el.firstChild;
4401                 }else{
4402                     el.innerHTML = html;
4403                     return el.firstChild;
4404                 }
4405             case "beforeend":
4406                 if(el.lastChild){
4407                     range.setStartAfter(el.lastChild);
4408                     frag = range.createContextualFragment(html);
4409                     el.appendChild(frag);
4410                     return el.lastChild;
4411                 }else{
4412                     el.innerHTML = html;
4413                     return el.lastChild;
4414                 }
4415             case "afterend":
4416                 range.setStartAfter(el);
4417                 frag = range.createContextualFragment(html);
4418                 el.parentNode.insertBefore(frag, el.nextSibling);
4419                 return el.nextSibling;
4420             }
4421             throw 'Illegal insertion point -> "' + where + '"';
4422     },
4423
4424     /**
4425      * Creates new Dom element(s) and inserts them before el
4426      * @param {String/HTMLElement/Element} el The context element
4427      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4428      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4429      * @return {HTMLElement/Roo.Element} The new node
4430      */
4431     insertBefore : function(el, o, returnElement){
4432         return this.doInsert(el, o, returnElement, "beforeBegin");
4433     },
4434
4435     /**
4436      * Creates new Dom element(s) and inserts them after el
4437      * @param {String/HTMLElement/Element} el The context element
4438      * @param {Object} o The Dom object spec (and children)
4439      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4440      * @return {HTMLElement/Roo.Element} The new node
4441      */
4442     insertAfter : function(el, o, returnElement){
4443         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4444     },
4445
4446     /**
4447      * Creates new Dom element(s) and inserts them as the first child of el
4448      * @param {String/HTMLElement/Element} el The context element
4449      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4450      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4451      * @return {HTMLElement/Roo.Element} The new node
4452      */
4453     insertFirst : function(el, o, returnElement){
4454         return this.doInsert(el, o, returnElement, "afterBegin");
4455     },
4456
4457     // private
4458     doInsert : function(el, o, returnElement, pos, sibling){
4459         el = Roo.getDom(el);
4460         var newNode;
4461         if(this.useDom || o.ns){
4462             newNode = createDom(o, null);
4463             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4464         }else{
4465             var html = createHtml(o);
4466             newNode = this.insertHtml(pos, el, html);
4467         }
4468         return returnElement ? Roo.get(newNode, true) : newNode;
4469     },
4470
4471     /**
4472      * Creates new Dom element(s) and appends them to el
4473      * @param {String/HTMLElement/Element} el The context element
4474      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476      * @return {HTMLElement/Roo.Element} The new node
4477      */
4478     append : function(el, o, returnElement){
4479         el = Roo.getDom(el);
4480         var newNode;
4481         if(this.useDom || o.ns){
4482             newNode = createDom(o, null);
4483             el.appendChild(newNode);
4484         }else{
4485             var html = createHtml(o);
4486             newNode = this.insertHtml("beforeEnd", el, html);
4487         }
4488         return returnElement ? Roo.get(newNode, true) : newNode;
4489     },
4490
4491     /**
4492      * Creates new Dom element(s) and overwrites the contents of el with them
4493      * @param {String/HTMLElement/Element} el The context element
4494      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4495      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4496      * @return {HTMLElement/Roo.Element} The new node
4497      */
4498     overwrite : function(el, o, returnElement){
4499         Roo.log('run???');
4500         el = Roo.getDom(el);
4501         if (o.ns) {
4502           
4503             while (el.childNodes.length) {
4504                 el.removeChild(el.firstChild);
4505             }
4506             createDom(o, el);
4507         } else {
4508             el.innerHTML = createHtml(o);   
4509         }
4510         
4511         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4512     },
4513
4514     /**
4515      * Creates a new Roo.DomHelper.Template from the Dom object spec
4516      * @param {Object} o The Dom object spec (and children)
4517      * @return {Roo.DomHelper.Template} The new template
4518      */
4519     createTemplate : function(o){
4520         var html = createHtml(o);
4521         return new Roo.Template(html);
4522     }
4523     };
4524 }();
4525 /*
4526  * Based on:
4527  * Ext JS Library 1.1.1
4528  * Copyright(c) 2006-2007, Ext JS, LLC.
4529  *
4530  * Originally Released Under LGPL - original licence link has changed is not relivant.
4531  *
4532  * Fork - LGPL
4533  * <script type="text/javascript">
4534  */
4535  
4536 /**
4537 * @class Roo.Template
4538 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4539 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4540 * Usage:
4541 <pre><code>
4542 var t = new Roo.Template({
4543     html :  '&lt;div name="{id}"&gt;' + 
4544         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4545         '&lt;/div&gt;',
4546     myformat: function (value, allValues) {
4547         return 'XX' + value;
4548     }
4549 });
4550 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4551 </code></pre>
4552 * For more information see this blog post with examples:
4553 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4554      - Create Elements using DOM, HTML fragments and Templates</a>. 
4555 * @constructor
4556 * @param {Object} cfg - Configuration object.
4557 */
4558 Roo.Template = function(cfg){
4559     // BC!
4560     if(cfg instanceof Array){
4561         cfg = cfg.join("");
4562     }else if(arguments.length > 1){
4563         cfg = Array.prototype.join.call(arguments, "");
4564     }
4565     
4566     
4567     if (typeof(cfg) == 'object') {
4568         Roo.apply(this,cfg)
4569     } else {
4570         // bc
4571         this.html = cfg;
4572     }
4573     if (this.url) {
4574         this.load();
4575     }
4576     
4577 };
4578 Roo.Template.prototype = {
4579     
4580     /**
4581      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4582      *                    it should be fixed so that template is observable...
4583      */
4584     url : false,
4585     /**
4586      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4587      */
4588     html : '',
4589     /**
4590      * Returns an HTML fragment of this template with the specified values applied.
4591      * @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'})
4592      * @return {String} The HTML fragment
4593      */
4594     applyTemplate : function(values){
4595         try {
4596            
4597             if(this.compiled){
4598                 return this.compiled(values);
4599             }
4600             var useF = this.disableFormats !== true;
4601             var fm = Roo.util.Format, tpl = this;
4602             var fn = function(m, name, format, args){
4603                 if(format && useF){
4604                     if(format.substr(0, 5) == "this."){
4605                         return tpl.call(format.substr(5), values[name], values);
4606                     }else{
4607                         if(args){
4608                             // quoted values are required for strings in compiled templates, 
4609                             // but for non compiled we need to strip them
4610                             // quoted reversed for jsmin
4611                             var re = /^\s*['"](.*)["']\s*$/;
4612                             args = args.split(',');
4613                             for(var i = 0, len = args.length; i < len; i++){
4614                                 args[i] = args[i].replace(re, "$1");
4615                             }
4616                             args = [values[name]].concat(args);
4617                         }else{
4618                             args = [values[name]];
4619                         }
4620                         return fm[format].apply(fm, args);
4621                     }
4622                 }else{
4623                     return values[name] !== undefined ? values[name] : "";
4624                 }
4625             };
4626             return this.html.replace(this.re, fn);
4627         } catch (e) {
4628             Roo.log(e);
4629             throw e;
4630         }
4631          
4632     },
4633     
4634     loading : false,
4635       
4636     load : function ()
4637     {
4638          
4639         if (this.loading) {
4640             return;
4641         }
4642         var _t = this;
4643         
4644         this.loading = true;
4645         this.compiled = false;
4646         
4647         var cx = new Roo.data.Connection();
4648         cx.request({
4649             url : this.url,
4650             method : 'GET',
4651             success : function (response) {
4652                 _t.loading = false;
4653                 _t.html = response.responseText;
4654                 _t.url = false;
4655                 _t.compile();
4656              },
4657             failure : function(response) {
4658                 Roo.log("Template failed to load from " + _t.url);
4659                 _t.loading = false;
4660             }
4661         });
4662     },
4663
4664     /**
4665      * Sets the HTML used as the template and optionally compiles it.
4666      * @param {String} html
4667      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4668      * @return {Roo.Template} this
4669      */
4670     set : function(html, compile){
4671         this.html = html;
4672         this.compiled = null;
4673         if(compile){
4674             this.compile();
4675         }
4676         return this;
4677     },
4678     
4679     /**
4680      * True to disable format functions (defaults to false)
4681      * @type Boolean
4682      */
4683     disableFormats : false,
4684     
4685     /**
4686     * The regular expression used to match template variables 
4687     * @type RegExp
4688     * @property 
4689     */
4690     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4691     
4692     /**
4693      * Compiles the template into an internal function, eliminating the RegEx overhead.
4694      * @return {Roo.Template} this
4695      */
4696     compile : function(){
4697         var fm = Roo.util.Format;
4698         var useF = this.disableFormats !== true;
4699         var sep = Roo.isGecko ? "+" : ",";
4700         var fn = function(m, name, format, args){
4701             if(format && useF){
4702                 args = args ? ',' + args : "";
4703                 if(format.substr(0, 5) != "this."){
4704                     format = "fm." + format + '(';
4705                 }else{
4706                     format = 'this.call("'+ format.substr(5) + '", ';
4707                     args = ", values";
4708                 }
4709             }else{
4710                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4711             }
4712             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4713         };
4714         var body;
4715         // branched to use + in gecko and [].join() in others
4716         if(Roo.isGecko){
4717             body = "this.compiled = function(values){ return '" +
4718                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4719                     "';};";
4720         }else{
4721             body = ["this.compiled = function(values){ return ['"];
4722             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4723             body.push("'].join('');};");
4724             body = body.join('');
4725         }
4726         /**
4727          * eval:var:values
4728          * eval:var:fm
4729          */
4730         eval(body);
4731         return this;
4732     },
4733     
4734     // private function used to call members
4735     call : function(fnName, value, allValues){
4736         return this[fnName](value, allValues);
4737     },
4738     
4739     /**
4740      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4741      * @param {String/HTMLElement/Roo.Element} el The context element
4742      * @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'})
4743      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4744      * @return {HTMLElement/Roo.Element} The new node or Element
4745      */
4746     insertFirst: function(el, values, returnElement){
4747         return this.doInsert('afterBegin', el, values, returnElement);
4748     },
4749
4750     /**
4751      * Applies the supplied values to the template and inserts the new node(s) before el.
4752      * @param {String/HTMLElement/Roo.Element} el The context element
4753      * @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'})
4754      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4755      * @return {HTMLElement/Roo.Element} The new node or Element
4756      */
4757     insertBefore: function(el, values, returnElement){
4758         return this.doInsert('beforeBegin', el, values, returnElement);
4759     },
4760
4761     /**
4762      * Applies the supplied values to the template and inserts the new node(s) after el.
4763      * @param {String/HTMLElement/Roo.Element} el The context element
4764      * @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'})
4765      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4766      * @return {HTMLElement/Roo.Element} The new node or Element
4767      */
4768     insertAfter : function(el, values, returnElement){
4769         return this.doInsert('afterEnd', el, values, returnElement);
4770     },
4771     
4772     /**
4773      * Applies the supplied values to the template and appends the new node(s) to el.
4774      * @param {String/HTMLElement/Roo.Element} el The context element
4775      * @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'})
4776      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4777      * @return {HTMLElement/Roo.Element} The new node or Element
4778      */
4779     append : function(el, values, returnElement){
4780         return this.doInsert('beforeEnd', el, values, returnElement);
4781     },
4782
4783     doInsert : function(where, el, values, returnEl){
4784         el = Roo.getDom(el);
4785         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4786         return returnEl ? Roo.get(newNode, true) : newNode;
4787     },
4788
4789     /**
4790      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4791      * @param {String/HTMLElement/Roo.Element} el The context element
4792      * @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'})
4793      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4794      * @return {HTMLElement/Roo.Element} The new node or Element
4795      */
4796     overwrite : function(el, values, returnElement){
4797         el = Roo.getDom(el);
4798         el.innerHTML = this.applyTemplate(values);
4799         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4800     }
4801 };
4802 /**
4803  * Alias for {@link #applyTemplate}
4804  * @method
4805  */
4806 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4807
4808 // backwards compat
4809 Roo.DomHelper.Template = Roo.Template;
4810
4811 /**
4812  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4813  * @param {String/HTMLElement} el A DOM element or its id
4814  * @returns {Roo.Template} The created template
4815  * @static
4816  */
4817 Roo.Template.from = function(el){
4818     el = Roo.getDom(el);
4819     return new Roo.Template(el.value || el.innerHTML);
4820 };/*
4821  * Based on:
4822  * Ext JS Library 1.1.1
4823  * Copyright(c) 2006-2007, Ext JS, LLC.
4824  *
4825  * Originally Released Under LGPL - original licence link has changed is not relivant.
4826  *
4827  * Fork - LGPL
4828  * <script type="text/javascript">
4829  */
4830  
4831
4832 /*
4833  * This is code is also distributed under MIT license for use
4834  * with jQuery and prototype JavaScript libraries.
4835  */
4836 /**
4837  * @class Roo.DomQuery
4838 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).
4839 <p>
4840 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>
4841
4842 <p>
4843 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.
4844 </p>
4845 <h4>Element Selectors:</h4>
4846 <ul class="list">
4847     <li> <b>*</b> any element</li>
4848     <li> <b>E</b> an element with the tag E</li>
4849     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4850     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4851     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4852     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4853 </ul>
4854 <h4>Attribute Selectors:</h4>
4855 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4856 <ul class="list">
4857     <li> <b>E[foo]</b> has an attribute "foo"</li>
4858     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4859     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4860     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4861     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4862     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4863     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4864 </ul>
4865 <h4>Pseudo Classes:</h4>
4866 <ul class="list">
4867     <li> <b>E:first-child</b> E is the first child of its parent</li>
4868     <li> <b>E:last-child</b> E is the last child of its parent</li>
4869     <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>
4870     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4871     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4872     <li> <b>E:only-child</b> E is the only child of its parent</li>
4873     <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>
4874     <li> <b>E:first</b> the first E in the resultset</li>
4875     <li> <b>E:last</b> the last E in the resultset</li>
4876     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4877     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4878     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4879     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4880     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4881     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4882     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4883     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4884     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4885 </ul>
4886 <h4>CSS Value Selectors:</h4>
4887 <ul class="list">
4888     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4889     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4890     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4891     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4892     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4893     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4894 </ul>
4895  * @singleton
4896  */
4897 Roo.DomQuery = function(){
4898     var cache = {}, simpleCache = {}, valueCache = {};
4899     var nonSpace = /\S/;
4900     var trimRe = /^\s+|\s+$/g;
4901     var tplRe = /\{(\d+)\}/g;
4902     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4903     var tagTokenRe = /^(#)?([\w-\*]+)/;
4904     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4905
4906     function child(p, index){
4907         var i = 0;
4908         var n = p.firstChild;
4909         while(n){
4910             if(n.nodeType == 1){
4911                if(++i == index){
4912                    return n;
4913                }
4914             }
4915             n = n.nextSibling;
4916         }
4917         return null;
4918     };
4919
4920     function next(n){
4921         while((n = n.nextSibling) && n.nodeType != 1);
4922         return n;
4923     };
4924
4925     function prev(n){
4926         while((n = n.previousSibling) && n.nodeType != 1);
4927         return n;
4928     };
4929
4930     function children(d){
4931         var n = d.firstChild, ni = -1;
4932             while(n){
4933                 var nx = n.nextSibling;
4934                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4935                     d.removeChild(n);
4936                 }else{
4937                     n.nodeIndex = ++ni;
4938                 }
4939                 n = nx;
4940             }
4941             return this;
4942         };
4943
4944     function byClassName(c, a, v){
4945         if(!v){
4946             return c;
4947         }
4948         var r = [], ri = -1, cn;
4949         for(var i = 0, ci; ci = c[i]; i++){
4950             if((' '+ci.className+' ').indexOf(v) != -1){
4951                 r[++ri] = ci;
4952             }
4953         }
4954         return r;
4955     };
4956
4957     function attrValue(n, attr){
4958         if(!n.tagName && typeof n.length != "undefined"){
4959             n = n[0];
4960         }
4961         if(!n){
4962             return null;
4963         }
4964         if(attr == "for"){
4965             return n.htmlFor;
4966         }
4967         if(attr == "class" || attr == "className"){
4968             return n.className;
4969         }
4970         return n.getAttribute(attr) || n[attr];
4971
4972     };
4973
4974     function getNodes(ns, mode, tagName){
4975         var result = [], ri = -1, cs;
4976         if(!ns){
4977             return result;
4978         }
4979         tagName = tagName || "*";
4980         if(typeof ns.getElementsByTagName != "undefined"){
4981             ns = [ns];
4982         }
4983         if(!mode){
4984             for(var i = 0, ni; ni = ns[i]; i++){
4985                 cs = ni.getElementsByTagName(tagName);
4986                 for(var j = 0, ci; ci = cs[j]; j++){
4987                     result[++ri] = ci;
4988                 }
4989             }
4990         }else if(mode == "/" || mode == ">"){
4991             var utag = tagName.toUpperCase();
4992             for(var i = 0, ni, cn; ni = ns[i]; i++){
4993                 cn = ni.children || ni.childNodes;
4994                 for(var j = 0, cj; cj = cn[j]; j++){
4995                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4996                         result[++ri] = cj;
4997                     }
4998                 }
4999             }
5000         }else if(mode == "+"){
5001             var utag = tagName.toUpperCase();
5002             for(var i = 0, n; n = ns[i]; i++){
5003                 while((n = n.nextSibling) && n.nodeType != 1);
5004                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5005                     result[++ri] = n;
5006                 }
5007             }
5008         }else if(mode == "~"){
5009             for(var i = 0, n; n = ns[i]; i++){
5010                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5011                 if(n){
5012                     result[++ri] = n;
5013                 }
5014             }
5015         }
5016         return result;
5017     };
5018
5019     function concat(a, b){
5020         if(b.slice){
5021             return a.concat(b);
5022         }
5023         for(var i = 0, l = b.length; i < l; i++){
5024             a[a.length] = b[i];
5025         }
5026         return a;
5027     }
5028
5029     function byTag(cs, tagName){
5030         if(cs.tagName || cs == document){
5031             cs = [cs];
5032         }
5033         if(!tagName){
5034             return cs;
5035         }
5036         var r = [], ri = -1;
5037         tagName = tagName.toLowerCase();
5038         for(var i = 0, ci; ci = cs[i]; i++){
5039             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5040                 r[++ri] = ci;
5041             }
5042         }
5043         return r;
5044     };
5045
5046     function byId(cs, attr, id){
5047         if(cs.tagName || cs == document){
5048             cs = [cs];
5049         }
5050         if(!id){
5051             return cs;
5052         }
5053         var r = [], ri = -1;
5054         for(var i = 0,ci; ci = cs[i]; i++){
5055             if(ci && ci.id == id){
5056                 r[++ri] = ci;
5057                 return r;
5058             }
5059         }
5060         return r;
5061     };
5062
5063     function byAttribute(cs, attr, value, op, custom){
5064         var r = [], ri = -1, st = custom=="{";
5065         var f = Roo.DomQuery.operators[op];
5066         for(var i = 0, ci; ci = cs[i]; i++){
5067             var a;
5068             if(st){
5069                 a = Roo.DomQuery.getStyle(ci, attr);
5070             }
5071             else if(attr == "class" || attr == "className"){
5072                 a = ci.className;
5073             }else if(attr == "for"){
5074                 a = ci.htmlFor;
5075             }else if(attr == "href"){
5076                 a = ci.getAttribute("href", 2);
5077             }else{
5078                 a = ci.getAttribute(attr);
5079             }
5080             if((f && f(a, value)) || (!f && a)){
5081                 r[++ri] = ci;
5082             }
5083         }
5084         return r;
5085     };
5086
5087     function byPseudo(cs, name, value){
5088         return Roo.DomQuery.pseudos[name](cs, value);
5089     };
5090
5091     // This is for IE MSXML which does not support expandos.
5092     // IE runs the same speed using setAttribute, however FF slows way down
5093     // and Safari completely fails so they need to continue to use expandos.
5094     var isIE = window.ActiveXObject ? true : false;
5095
5096     // this eval is stop the compressor from
5097     // renaming the variable to something shorter
5098     
5099     /** eval:var:batch */
5100     var batch = 30803; 
5101
5102     var key = 30803;
5103
5104     function nodupIEXml(cs){
5105         var d = ++key;
5106         cs[0].setAttribute("_nodup", d);
5107         var r = [cs[0]];
5108         for(var i = 1, len = cs.length; i < len; i++){
5109             var c = cs[i];
5110             if(!c.getAttribute("_nodup") != d){
5111                 c.setAttribute("_nodup", d);
5112                 r[r.length] = c;
5113             }
5114         }
5115         for(var i = 0, len = cs.length; i < len; i++){
5116             cs[i].removeAttribute("_nodup");
5117         }
5118         return r;
5119     }
5120
5121     function nodup(cs){
5122         if(!cs){
5123             return [];
5124         }
5125         var len = cs.length, c, i, r = cs, cj, ri = -1;
5126         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5127             return cs;
5128         }
5129         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5130             return nodupIEXml(cs);
5131         }
5132         var d = ++key;
5133         cs[0]._nodup = d;
5134         for(i = 1; c = cs[i]; i++){
5135             if(c._nodup != d){
5136                 c._nodup = d;
5137             }else{
5138                 r = [];
5139                 for(var j = 0; j < i; j++){
5140                     r[++ri] = cs[j];
5141                 }
5142                 for(j = i+1; cj = cs[j]; j++){
5143                     if(cj._nodup != d){
5144                         cj._nodup = d;
5145                         r[++ri] = cj;
5146                     }
5147                 }
5148                 return r;
5149             }
5150         }
5151         return r;
5152     }
5153
5154     function quickDiffIEXml(c1, c2){
5155         var d = ++key;
5156         for(var i = 0, len = c1.length; i < len; i++){
5157             c1[i].setAttribute("_qdiff", d);
5158         }
5159         var r = [];
5160         for(var i = 0, len = c2.length; i < len; i++){
5161             if(c2[i].getAttribute("_qdiff") != d){
5162                 r[r.length] = c2[i];
5163             }
5164         }
5165         for(var i = 0, len = c1.length; i < len; i++){
5166            c1[i].removeAttribute("_qdiff");
5167         }
5168         return r;
5169     }
5170
5171     function quickDiff(c1, c2){
5172         var len1 = c1.length;
5173         if(!len1){
5174             return c2;
5175         }
5176         if(isIE && c1[0].selectSingleNode){
5177             return quickDiffIEXml(c1, c2);
5178         }
5179         var d = ++key;
5180         for(var i = 0; i < len1; i++){
5181             c1[i]._qdiff = d;
5182         }
5183         var r = [];
5184         for(var i = 0, len = c2.length; i < len; i++){
5185             if(c2[i]._qdiff != d){
5186                 r[r.length] = c2[i];
5187             }
5188         }
5189         return r;
5190     }
5191
5192     function quickId(ns, mode, root, id){
5193         if(ns == root){
5194            var d = root.ownerDocument || root;
5195            return d.getElementById(id);
5196         }
5197         ns = getNodes(ns, mode, "*");
5198         return byId(ns, null, id);
5199     }
5200
5201     return {
5202         getStyle : function(el, name){
5203             return Roo.fly(el).getStyle(name);
5204         },
5205         /**
5206          * Compiles a selector/xpath query into a reusable function. The returned function
5207          * takes one parameter "root" (optional), which is the context node from where the query should start.
5208          * @param {String} selector The selector/xpath query
5209          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5210          * @return {Function}
5211          */
5212         compile : function(path, type){
5213             type = type || "select";
5214             
5215             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5216             var q = path, mode, lq;
5217             var tk = Roo.DomQuery.matchers;
5218             var tklen = tk.length;
5219             var mm;
5220
5221             // accept leading mode switch
5222             var lmode = q.match(modeRe);
5223             if(lmode && lmode[1]){
5224                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5225                 q = q.replace(lmode[1], "");
5226             }
5227             // strip leading slashes
5228             while(path.substr(0, 1)=="/"){
5229                 path = path.substr(1);
5230             }
5231
5232             while(q && lq != q){
5233                 lq = q;
5234                 var tm = q.match(tagTokenRe);
5235                 if(type == "select"){
5236                     if(tm){
5237                         if(tm[1] == "#"){
5238                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5239                         }else{
5240                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5241                         }
5242                         q = q.replace(tm[0], "");
5243                     }else if(q.substr(0, 1) != '@'){
5244                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5245                     }
5246                 }else{
5247                     if(tm){
5248                         if(tm[1] == "#"){
5249                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5250                         }else{
5251                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5252                         }
5253                         q = q.replace(tm[0], "");
5254                     }
5255                 }
5256                 while(!(mm = q.match(modeRe))){
5257                     var matched = false;
5258                     for(var j = 0; j < tklen; j++){
5259                         var t = tk[j];
5260                         var m = q.match(t.re);
5261                         if(m){
5262                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5263                                                     return m[i];
5264                                                 });
5265                             q = q.replace(m[0], "");
5266                             matched = true;
5267                             break;
5268                         }
5269                     }
5270                     // prevent infinite loop on bad selector
5271                     if(!matched){
5272                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5273                     }
5274                 }
5275                 if(mm[1]){
5276                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5277                     q = q.replace(mm[1], "");
5278                 }
5279             }
5280             fn[fn.length] = "return nodup(n);\n}";
5281             
5282              /** 
5283               * list of variables that need from compression as they are used by eval.
5284              *  eval:var:batch 
5285              *  eval:var:nodup
5286              *  eval:var:byTag
5287              *  eval:var:ById
5288              *  eval:var:getNodes
5289              *  eval:var:quickId
5290              *  eval:var:mode
5291              *  eval:var:root
5292              *  eval:var:n
5293              *  eval:var:byClassName
5294              *  eval:var:byPseudo
5295              *  eval:var:byAttribute
5296              *  eval:var:attrValue
5297              * 
5298              **/ 
5299             eval(fn.join(""));
5300             return f;
5301         },
5302
5303         /**
5304          * Selects a group of elements.
5305          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5306          * @param {Node} root (optional) The start of the query (defaults to document).
5307          * @return {Array}
5308          */
5309         select : function(path, root, type){
5310             if(!root || root == document){
5311                 root = document;
5312             }
5313             if(typeof root == "string"){
5314                 root = document.getElementById(root);
5315             }
5316             var paths = path.split(",");
5317             var results = [];
5318             for(var i = 0, len = paths.length; i < len; i++){
5319                 var p = paths[i].replace(trimRe, "");
5320                 if(!cache[p]){
5321                     cache[p] = Roo.DomQuery.compile(p);
5322                     if(!cache[p]){
5323                         throw p + " is not a valid selector";
5324                     }
5325                 }
5326                 var result = cache[p](root);
5327                 if(result && result != document){
5328                     results = results.concat(result);
5329                 }
5330             }
5331             if(paths.length > 1){
5332                 return nodup(results);
5333             }
5334             return results;
5335         },
5336
5337         /**
5338          * Selects a single element.
5339          * @param {String} selector The selector/xpath query
5340          * @param {Node} root (optional) The start of the query (defaults to document).
5341          * @return {Element}
5342          */
5343         selectNode : function(path, root){
5344             return Roo.DomQuery.select(path, root)[0];
5345         },
5346
5347         /**
5348          * Selects the value of a node, optionally replacing null with the defaultValue.
5349          * @param {String} selector The selector/xpath query
5350          * @param {Node} root (optional) The start of the query (defaults to document).
5351          * @param {String} defaultValue
5352          */
5353         selectValue : function(path, root, defaultValue){
5354             path = path.replace(trimRe, "");
5355             if(!valueCache[path]){
5356                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5357             }
5358             var n = valueCache[path](root);
5359             n = n[0] ? n[0] : n;
5360             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5361             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5362         },
5363
5364         /**
5365          * Selects the value of a node, parsing integers and floats.
5366          * @param {String} selector The selector/xpath query
5367          * @param {Node} root (optional) The start of the query (defaults to document).
5368          * @param {Number} defaultValue
5369          * @return {Number}
5370          */
5371         selectNumber : function(path, root, defaultValue){
5372             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5373             return parseFloat(v);
5374         },
5375
5376         /**
5377          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5378          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5379          * @param {String} selector The simple selector to test
5380          * @return {Boolean}
5381          */
5382         is : function(el, ss){
5383             if(typeof el == "string"){
5384                 el = document.getElementById(el);
5385             }
5386             var isArray = (el instanceof Array);
5387             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5388             return isArray ? (result.length == el.length) : (result.length > 0);
5389         },
5390
5391         /**
5392          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5393          * @param {Array} el An array of elements to filter
5394          * @param {String} selector The simple selector to test
5395          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5396          * the selector instead of the ones that match
5397          * @return {Array}
5398          */
5399         filter : function(els, ss, nonMatches){
5400             ss = ss.replace(trimRe, "");
5401             if(!simpleCache[ss]){
5402                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5403             }
5404             var result = simpleCache[ss](els);
5405             return nonMatches ? quickDiff(result, els) : result;
5406         },
5407
5408         /**
5409          * Collection of matching regular expressions and code snippets.
5410          */
5411         matchers : [{
5412                 re: /^\.([\w-]+)/,
5413                 select: 'n = byClassName(n, null, " {1} ");'
5414             }, {
5415                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5416                 select: 'n = byPseudo(n, "{1}", "{2}");'
5417             },{
5418                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5419                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5420             }, {
5421                 re: /^#([\w-]+)/,
5422                 select: 'n = byId(n, null, "{1}");'
5423             },{
5424                 re: /^@([\w-]+)/,
5425                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5426             }
5427         ],
5428
5429         /**
5430          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5431          * 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;.
5432          */
5433         operators : {
5434             "=" : function(a, v){
5435                 return a == v;
5436             },
5437             "!=" : function(a, v){
5438                 return a != v;
5439             },
5440             "^=" : function(a, v){
5441                 return a && a.substr(0, v.length) == v;
5442             },
5443             "$=" : function(a, v){
5444                 return a && a.substr(a.length-v.length) == v;
5445             },
5446             "*=" : function(a, v){
5447                 return a && a.indexOf(v) !== -1;
5448             },
5449             "%=" : function(a, v){
5450                 return (a % v) == 0;
5451             },
5452             "|=" : function(a, v){
5453                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5454             },
5455             "~=" : function(a, v){
5456                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5457             }
5458         },
5459
5460         /**
5461          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5462          * and the argument (if any) supplied in the selector.
5463          */
5464         pseudos : {
5465             "first-child" : function(c){
5466                 var r = [], ri = -1, n;
5467                 for(var i = 0, ci; ci = n = c[i]; i++){
5468                     while((n = n.previousSibling) && n.nodeType != 1);
5469                     if(!n){
5470                         r[++ri] = ci;
5471                     }
5472                 }
5473                 return r;
5474             },
5475
5476             "last-child" : function(c){
5477                 var r = [], ri = -1, n;
5478                 for(var i = 0, ci; ci = n = c[i]; i++){
5479                     while((n = n.nextSibling) && n.nodeType != 1);
5480                     if(!n){
5481                         r[++ri] = ci;
5482                     }
5483                 }
5484                 return r;
5485             },
5486
5487             "nth-child" : function(c, a) {
5488                 var r = [], ri = -1;
5489                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5490                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5491                 for(var i = 0, n; n = c[i]; i++){
5492                     var pn = n.parentNode;
5493                     if (batch != pn._batch) {
5494                         var j = 0;
5495                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5496                             if(cn.nodeType == 1){
5497                                cn.nodeIndex = ++j;
5498                             }
5499                         }
5500                         pn._batch = batch;
5501                     }
5502                     if (f == 1) {
5503                         if (l == 0 || n.nodeIndex == l){
5504                             r[++ri] = n;
5505                         }
5506                     } else if ((n.nodeIndex + l) % f == 0){
5507                         r[++ri] = n;
5508                     }
5509                 }
5510
5511                 return r;
5512             },
5513
5514             "only-child" : function(c){
5515                 var r = [], ri = -1;;
5516                 for(var i = 0, ci; ci = c[i]; i++){
5517                     if(!prev(ci) && !next(ci)){
5518                         r[++ri] = ci;
5519                     }
5520                 }
5521                 return r;
5522             },
5523
5524             "empty" : function(c){
5525                 var r = [], ri = -1;
5526                 for(var i = 0, ci; ci = c[i]; i++){
5527                     var cns = ci.childNodes, j = 0, cn, empty = true;
5528                     while(cn = cns[j]){
5529                         ++j;
5530                         if(cn.nodeType == 1 || cn.nodeType == 3){
5531                             empty = false;
5532                             break;
5533                         }
5534                     }
5535                     if(empty){
5536                         r[++ri] = ci;
5537                     }
5538                 }
5539                 return r;
5540             },
5541
5542             "contains" : function(c, v){
5543                 var r = [], ri = -1;
5544                 for(var i = 0, ci; ci = c[i]; i++){
5545                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5546                         r[++ri] = ci;
5547                     }
5548                 }
5549                 return r;
5550             },
5551
5552             "nodeValue" : function(c, v){
5553                 var r = [], ri = -1;
5554                 for(var i = 0, ci; ci = c[i]; i++){
5555                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5556                         r[++ri] = ci;
5557                     }
5558                 }
5559                 return r;
5560             },
5561
5562             "checked" : function(c){
5563                 var r = [], ri = -1;
5564                 for(var i = 0, ci; ci = c[i]; i++){
5565                     if(ci.checked == true){
5566                         r[++ri] = ci;
5567                     }
5568                 }
5569                 return r;
5570             },
5571
5572             "not" : function(c, ss){
5573                 return Roo.DomQuery.filter(c, ss, true);
5574             },
5575
5576             "odd" : function(c){
5577                 return this["nth-child"](c, "odd");
5578             },
5579
5580             "even" : function(c){
5581                 return this["nth-child"](c, "even");
5582             },
5583
5584             "nth" : function(c, a){
5585                 return c[a-1] || [];
5586             },
5587
5588             "first" : function(c){
5589                 return c[0] || [];
5590             },
5591
5592             "last" : function(c){
5593                 return c[c.length-1] || [];
5594             },
5595
5596             "has" : function(c, ss){
5597                 var s = Roo.DomQuery.select;
5598                 var r = [], ri = -1;
5599                 for(var i = 0, ci; ci = c[i]; i++){
5600                     if(s(ss, ci).length > 0){
5601                         r[++ri] = ci;
5602                     }
5603                 }
5604                 return r;
5605             },
5606
5607             "next" : function(c, ss){
5608                 var is = Roo.DomQuery.is;
5609                 var r = [], ri = -1;
5610                 for(var i = 0, ci; ci = c[i]; i++){
5611                     var n = next(ci);
5612                     if(n && is(n, ss)){
5613                         r[++ri] = ci;
5614                     }
5615                 }
5616                 return r;
5617             },
5618
5619             "prev" : function(c, ss){
5620                 var is = Roo.DomQuery.is;
5621                 var r = [], ri = -1;
5622                 for(var i = 0, ci; ci = c[i]; i++){
5623                     var n = prev(ci);
5624                     if(n && is(n, ss)){
5625                         r[++ri] = ci;
5626                     }
5627                 }
5628                 return r;
5629             }
5630         }
5631     };
5632 }();
5633
5634 /**
5635  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5636  * @param {String} path The selector/xpath query
5637  * @param {Node} root (optional) The start of the query (defaults to document).
5638  * @return {Array}
5639  * @member Roo
5640  * @method query
5641  */
5642 Roo.query = Roo.DomQuery.select;
5643 /*
5644  * Based on:
5645  * Ext JS Library 1.1.1
5646  * Copyright(c) 2006-2007, Ext JS, LLC.
5647  *
5648  * Originally Released Under LGPL - original licence link has changed is not relivant.
5649  *
5650  * Fork - LGPL
5651  * <script type="text/javascript">
5652  */
5653
5654 /**
5655  * @class Roo.util.Observable
5656  * Base class that provides a common interface for publishing events. Subclasses are expected to
5657  * to have a property "events" with all the events defined.<br>
5658  * For example:
5659  * <pre><code>
5660  Employee = function(name){
5661     this.name = name;
5662     this.addEvents({
5663         "fired" : true,
5664         "quit" : true
5665     });
5666  }
5667  Roo.extend(Employee, Roo.util.Observable);
5668 </code></pre>
5669  * @param {Object} config properties to use (incuding events / listeners)
5670  */
5671
5672 Roo.util.Observable = function(cfg){
5673     
5674     cfg = cfg|| {};
5675     this.addEvents(cfg.events || {});
5676     if (cfg.events) {
5677         delete cfg.events; // make sure
5678     }
5679      
5680     Roo.apply(this, cfg);
5681     
5682     if(this.listeners){
5683         this.on(this.listeners);
5684         delete this.listeners;
5685     }
5686 };
5687 Roo.util.Observable.prototype = {
5688     /** 
5689  * @cfg {Object} listeners  list of events and functions to call for this object, 
5690  * For example :
5691  * <pre><code>
5692     listeners :  { 
5693        'click' : function(e) {
5694            ..... 
5695         } ,
5696         .... 
5697     } 
5698   </code></pre>
5699  */
5700     
5701     
5702     /**
5703      * Fires the specified event with the passed parameters (minus the event name).
5704      * @param {String} eventName
5705      * @param {Object...} args Variable number of parameters are passed to handlers
5706      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5707      */
5708     fireEvent : function(){
5709         var ce = this.events[arguments[0].toLowerCase()];
5710         if(typeof ce == "object"){
5711             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5712         }else{
5713             return true;
5714         }
5715     },
5716
5717     // private
5718     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5719
5720     /**
5721      * Appends an event handler to this component
5722      * @param {String}   eventName The type of event to listen for
5723      * @param {Function} handler The method the event invokes
5724      * @param {Object}   scope (optional) The scope in which to execute the handler
5725      * function. The handler function's "this" context.
5726      * @param {Object}   options (optional) An object containing handler configuration
5727      * properties. This may contain any of the following properties:<ul>
5728      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5729      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5730      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5731      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5732      * by the specified number of milliseconds. If the event fires again within that time, the original
5733      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5734      * </ul><br>
5735      * <p>
5736      * <b>Combining Options</b><br>
5737      * Using the options argument, it is possible to combine different types of listeners:<br>
5738      * <br>
5739      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5740                 <pre><code>
5741                 el.on('click', this.onClick, this, {
5742                         single: true,
5743                 delay: 100,
5744                 forumId: 4
5745                 });
5746                 </code></pre>
5747      * <p>
5748      * <b>Attaching multiple handlers in 1 call</b><br>
5749      * The method also allows for a single argument to be passed which is a config object containing properties
5750      * which specify multiple handlers.
5751      * <pre><code>
5752                 el.on({
5753                         'click': {
5754                         fn: this.onClick,
5755                         scope: this,
5756                         delay: 100
5757                 }, 
5758                 'mouseover': {
5759                         fn: this.onMouseOver,
5760                         scope: this
5761                 },
5762                 'mouseout': {
5763                         fn: this.onMouseOut,
5764                         scope: this
5765                 }
5766                 });
5767                 </code></pre>
5768      * <p>
5769      * Or a shorthand syntax which passes the same scope object to all handlers:
5770         <pre><code>
5771                 el.on({
5772                         'click': this.onClick,
5773                 'mouseover': this.onMouseOver,
5774                 'mouseout': this.onMouseOut,
5775                 scope: this
5776                 });
5777                 </code></pre>
5778      */
5779     addListener : function(eventName, fn, scope, o){
5780         if(typeof eventName == "object"){
5781             o = eventName;
5782             for(var e in o){
5783                 if(this.filterOptRe.test(e)){
5784                     continue;
5785                 }
5786                 if(typeof o[e] == "function"){
5787                     // shared options
5788                     this.addListener(e, o[e], o.scope,  o);
5789                 }else{
5790                     // individual options
5791                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5792                 }
5793             }
5794             return;
5795         }
5796         o = (!o || typeof o == "boolean") ? {} : o;
5797         eventName = eventName.toLowerCase();
5798         var ce = this.events[eventName] || true;
5799         if(typeof ce == "boolean"){
5800             ce = new Roo.util.Event(this, eventName);
5801             this.events[eventName] = ce;
5802         }
5803         ce.addListener(fn, scope, o);
5804     },
5805
5806     /**
5807      * Removes a listener
5808      * @param {String}   eventName     The type of event to listen for
5809      * @param {Function} handler        The handler to remove
5810      * @param {Object}   scope  (optional) The scope (this object) for the handler
5811      */
5812     removeListener : function(eventName, fn, scope){
5813         var ce = this.events[eventName.toLowerCase()];
5814         if(typeof ce == "object"){
5815             ce.removeListener(fn, scope);
5816         }
5817     },
5818
5819     /**
5820      * Removes all listeners for this object
5821      */
5822     purgeListeners : function(){
5823         for(var evt in this.events){
5824             if(typeof this.events[evt] == "object"){
5825                  this.events[evt].clearListeners();
5826             }
5827         }
5828     },
5829
5830     relayEvents : function(o, events){
5831         var createHandler = function(ename){
5832             return function(){
5833                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5834             };
5835         };
5836         for(var i = 0, len = events.length; i < len; i++){
5837             var ename = events[i];
5838             if(!this.events[ename]){ this.events[ename] = true; };
5839             o.on(ename, createHandler(ename), this);
5840         }
5841     },
5842
5843     /**
5844      * Used to define events on this Observable
5845      * @param {Object} object The object with the events defined
5846      */
5847     addEvents : function(o){
5848         if(!this.events){
5849             this.events = {};
5850         }
5851         Roo.applyIf(this.events, o);
5852     },
5853
5854     /**
5855      * Checks to see if this object has any listeners for a specified event
5856      * @param {String} eventName The name of the event to check for
5857      * @return {Boolean} True if the event is being listened for, else false
5858      */
5859     hasListener : function(eventName){
5860         var e = this.events[eventName];
5861         return typeof e == "object" && e.listeners.length > 0;
5862     }
5863 };
5864 /**
5865  * Appends an event handler to this element (shorthand for addListener)
5866  * @param {String}   eventName     The type of event to listen for
5867  * @param {Function} handler        The method the event invokes
5868  * @param {Object}   scope (optional) The scope in which to execute the handler
5869  * function. The handler function's "this" context.
5870  * @param {Object}   options  (optional)
5871  * @method
5872  */
5873 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5874 /**
5875  * Removes a listener (shorthand for removeListener)
5876  * @param {String}   eventName     The type of event to listen for
5877  * @param {Function} handler        The handler to remove
5878  * @param {Object}   scope  (optional) The scope (this object) for the handler
5879  * @method
5880  */
5881 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5882
5883 /**
5884  * Starts capture on the specified Observable. All events will be passed
5885  * to the supplied function with the event name + standard signature of the event
5886  * <b>before</b> the event is fired. If the supplied function returns false,
5887  * the event will not fire.
5888  * @param {Observable} o The Observable to capture
5889  * @param {Function} fn The function to call
5890  * @param {Object} scope (optional) The scope (this object) for the fn
5891  * @static
5892  */
5893 Roo.util.Observable.capture = function(o, fn, scope){
5894     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5895 };
5896
5897 /**
5898  * Removes <b>all</b> added captures from the Observable.
5899  * @param {Observable} o The Observable to release
5900  * @static
5901  */
5902 Roo.util.Observable.releaseCapture = function(o){
5903     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5904 };
5905
5906 (function(){
5907
5908     var createBuffered = function(h, o, scope){
5909         var task = new Roo.util.DelayedTask();
5910         return function(){
5911             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5912         };
5913     };
5914
5915     var createSingle = function(h, e, fn, scope){
5916         return function(){
5917             e.removeListener(fn, scope);
5918             return h.apply(scope, arguments);
5919         };
5920     };
5921
5922     var createDelayed = function(h, o, scope){
5923         return function(){
5924             var args = Array.prototype.slice.call(arguments, 0);
5925             setTimeout(function(){
5926                 h.apply(scope, args);
5927             }, o.delay || 10);
5928         };
5929     };
5930
5931     Roo.util.Event = function(obj, name){
5932         this.name = name;
5933         this.obj = obj;
5934         this.listeners = [];
5935     };
5936
5937     Roo.util.Event.prototype = {
5938         addListener : function(fn, scope, options){
5939             var o = options || {};
5940             scope = scope || this.obj;
5941             if(!this.isListening(fn, scope)){
5942                 var l = {fn: fn, scope: scope, options: o};
5943                 var h = fn;
5944                 if(o.delay){
5945                     h = createDelayed(h, o, scope);
5946                 }
5947                 if(o.single){
5948                     h = createSingle(h, this, fn, scope);
5949                 }
5950                 if(o.buffer){
5951                     h = createBuffered(h, o, scope);
5952                 }
5953                 l.fireFn = h;
5954                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5955                     this.listeners.push(l);
5956                 }else{
5957                     this.listeners = this.listeners.slice(0);
5958                     this.listeners.push(l);
5959                 }
5960             }
5961         },
5962
5963         findListener : function(fn, scope){
5964             scope = scope || this.obj;
5965             var ls = this.listeners;
5966             for(var i = 0, len = ls.length; i < len; i++){
5967                 var l = ls[i];
5968                 if(l.fn == fn && l.scope == scope){
5969                     return i;
5970                 }
5971             }
5972             return -1;
5973         },
5974
5975         isListening : function(fn, scope){
5976             return this.findListener(fn, scope) != -1;
5977         },
5978
5979         removeListener : function(fn, scope){
5980             var index;
5981             if((index = this.findListener(fn, scope)) != -1){
5982                 if(!this.firing){
5983                     this.listeners.splice(index, 1);
5984                 }else{
5985                     this.listeners = this.listeners.slice(0);
5986                     this.listeners.splice(index, 1);
5987                 }
5988                 return true;
5989             }
5990             return false;
5991         },
5992
5993         clearListeners : function(){
5994             this.listeners = [];
5995         },
5996
5997         fire : function(){
5998             var ls = this.listeners, scope, len = ls.length;
5999             if(len > 0){
6000                 this.firing = true;
6001                 var args = Array.prototype.slice.call(arguments, 0);
6002                 for(var i = 0; i < len; i++){
6003                     var l = ls[i];
6004                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6005                         this.firing = false;
6006                         return false;
6007                     }
6008                 }
6009                 this.firing = false;
6010             }
6011             return true;
6012         }
6013     };
6014 })();/*
6015  * Based on:
6016  * Ext JS Library 1.1.1
6017  * Copyright(c) 2006-2007, Ext JS, LLC.
6018  *
6019  * Originally Released Under LGPL - original licence link has changed is not relivant.
6020  *
6021  * Fork - LGPL
6022  * <script type="text/javascript">
6023  */
6024
6025 /**
6026  * @class Roo.EventManager
6027  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6028  * several useful events directly.
6029  * See {@link Roo.EventObject} for more details on normalized event objects.
6030  * @singleton
6031  */
6032 Roo.EventManager = function(){
6033     var docReadyEvent, docReadyProcId, docReadyState = false;
6034     var resizeEvent, resizeTask, textEvent, textSize;
6035     var E = Roo.lib.Event;
6036     var D = Roo.lib.Dom;
6037
6038
6039     var fireDocReady = function(){
6040         if(!docReadyState){
6041             docReadyState = true;
6042             Roo.isReady = true;
6043             if(docReadyProcId){
6044                 clearInterval(docReadyProcId);
6045             }
6046             if(Roo.isGecko || Roo.isOpera) {
6047                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6048             }
6049             if(Roo.isIE){
6050                 var defer = document.getElementById("ie-deferred-loader");
6051                 if(defer){
6052                     defer.onreadystatechange = null;
6053                     defer.parentNode.removeChild(defer);
6054                 }
6055             }
6056             if(docReadyEvent){
6057                 docReadyEvent.fire();
6058                 docReadyEvent.clearListeners();
6059             }
6060         }
6061     };
6062     
6063     var initDocReady = function(){
6064         docReadyEvent = new Roo.util.Event();
6065         if(Roo.isGecko || Roo.isOpera) {
6066             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6067         }else if(Roo.isIE){
6068             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6069             var defer = document.getElementById("ie-deferred-loader");
6070             defer.onreadystatechange = function(){
6071                 if(this.readyState == "complete"){
6072                     fireDocReady();
6073                 }
6074             };
6075         }else if(Roo.isSafari){ 
6076             docReadyProcId = setInterval(function(){
6077                 var rs = document.readyState;
6078                 if(rs == "complete") {
6079                     fireDocReady();     
6080                  }
6081             }, 10);
6082         }
6083         // no matter what, make sure it fires on load
6084         E.on(window, "load", fireDocReady);
6085     };
6086
6087     var createBuffered = function(h, o){
6088         var task = new Roo.util.DelayedTask(h);
6089         return function(e){
6090             // create new event object impl so new events don't wipe out properties
6091             e = new Roo.EventObjectImpl(e);
6092             task.delay(o.buffer, h, null, [e]);
6093         };
6094     };
6095
6096     var createSingle = function(h, el, ename, fn){
6097         return function(e){
6098             Roo.EventManager.removeListener(el, ename, fn);
6099             h(e);
6100         };
6101     };
6102
6103     var createDelayed = function(h, o){
6104         return function(e){
6105             // create new event object impl so new events don't wipe out properties
6106             e = new Roo.EventObjectImpl(e);
6107             setTimeout(function(){
6108                 h(e);
6109             }, o.delay || 10);
6110         };
6111     };
6112
6113     var listen = function(element, ename, opt, fn, scope){
6114         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6115         fn = fn || o.fn; scope = scope || o.scope;
6116         var el = Roo.getDom(element);
6117         if(!el){
6118             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6119         }
6120         var h = function(e){
6121             e = Roo.EventObject.setEvent(e);
6122             var t;
6123             if(o.delegate){
6124                 t = e.getTarget(o.delegate, el);
6125                 if(!t){
6126                     return;
6127                 }
6128             }else{
6129                 t = e.target;
6130             }
6131             if(o.stopEvent === true){
6132                 e.stopEvent();
6133             }
6134             if(o.preventDefault === true){
6135                e.preventDefault();
6136             }
6137             if(o.stopPropagation === true){
6138                 e.stopPropagation();
6139             }
6140
6141             if(o.normalized === false){
6142                 e = e.browserEvent;
6143             }
6144
6145             fn.call(scope || el, e, t, o);
6146         };
6147         if(o.delay){
6148             h = createDelayed(h, o);
6149         }
6150         if(o.single){
6151             h = createSingle(h, el, ename, fn);
6152         }
6153         if(o.buffer){
6154             h = createBuffered(h, o);
6155         }
6156         fn._handlers = fn._handlers || [];
6157         fn._handlers.push([Roo.id(el), ename, h]);
6158
6159         E.on(el, ename, h);
6160         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6161             el.addEventListener("DOMMouseScroll", h, false);
6162             E.on(window, 'unload', function(){
6163                 el.removeEventListener("DOMMouseScroll", h, false);
6164             });
6165         }
6166         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6167             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6168         }
6169         return h;
6170     };
6171
6172     var stopListening = function(el, ename, fn){
6173         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6174         if(hds){
6175             for(var i = 0, len = hds.length; i < len; i++){
6176                 var h = hds[i];
6177                 if(h[0] == id && h[1] == ename){
6178                     hd = h[2];
6179                     hds.splice(i, 1);
6180                     break;
6181                 }
6182             }
6183         }
6184         E.un(el, ename, hd);
6185         el = Roo.getDom(el);
6186         if(ename == "mousewheel" && el.addEventListener){
6187             el.removeEventListener("DOMMouseScroll", hd, false);
6188         }
6189         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6190             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6191         }
6192     };
6193
6194     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6195     
6196     var pub = {
6197         
6198         
6199         /** 
6200          * Fix for doc tools
6201          * @scope Roo.EventManager
6202          */
6203         
6204         
6205         /** 
6206          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6207          * object with a Roo.EventObject
6208          * @param {Function} fn        The method the event invokes
6209          * @param {Object}   scope    An object that becomes the scope of the handler
6210          * @param {boolean}  override If true, the obj passed in becomes
6211          *                             the execution scope of the listener
6212          * @return {Function} The wrapped function
6213          * @deprecated
6214          */
6215         wrap : function(fn, scope, override){
6216             return function(e){
6217                 Roo.EventObject.setEvent(e);
6218                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6219             };
6220         },
6221         
6222         /**
6223      * Appends an event handler to an element (shorthand for addListener)
6224      * @param {String/HTMLElement}   element        The html element or id to assign the
6225      * @param {String}   eventName The type of event to listen for
6226      * @param {Function} handler The method the event invokes
6227      * @param {Object}   scope (optional) The scope in which to execute the handler
6228      * function. The handler function's "this" context.
6229      * @param {Object}   options (optional) An object containing handler configuration
6230      * properties. This may contain any of the following properties:<ul>
6231      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6232      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6233      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6234      * <li>preventDefault {Boolean} True to prevent the default action</li>
6235      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6236      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6237      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6238      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6239      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6240      * by the specified number of milliseconds. If the event fires again within that time, the original
6241      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6242      * </ul><br>
6243      * <p>
6244      * <b>Combining Options</b><br>
6245      * Using the options argument, it is possible to combine different types of listeners:<br>
6246      * <br>
6247      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6248      * Code:<pre><code>
6249 el.on('click', this.onClick, this, {
6250     single: true,
6251     delay: 100,
6252     stopEvent : true,
6253     forumId: 4
6254 });</code></pre>
6255      * <p>
6256      * <b>Attaching multiple handlers in 1 call</b><br>
6257       * The method also allows for a single argument to be passed which is a config object containing properties
6258      * which specify multiple handlers.
6259      * <p>
6260      * Code:<pre><code>
6261 el.on({
6262     'click' : {
6263         fn: this.onClick
6264         scope: this,
6265         delay: 100
6266     },
6267     'mouseover' : {
6268         fn: this.onMouseOver
6269         scope: this
6270     },
6271     'mouseout' : {
6272         fn: this.onMouseOut
6273         scope: this
6274     }
6275 });</code></pre>
6276      * <p>
6277      * Or a shorthand syntax:<br>
6278      * Code:<pre><code>
6279 el.on({
6280     'click' : this.onClick,
6281     'mouseover' : this.onMouseOver,
6282     'mouseout' : this.onMouseOut
6283     scope: this
6284 });</code></pre>
6285      */
6286         addListener : function(element, eventName, fn, scope, options){
6287             if(typeof eventName == "object"){
6288                 var o = eventName;
6289                 for(var e in o){
6290                     if(propRe.test(e)){
6291                         continue;
6292                     }
6293                     if(typeof o[e] == "function"){
6294                         // shared options
6295                         listen(element, e, o, o[e], o.scope);
6296                     }else{
6297                         // individual options
6298                         listen(element, e, o[e]);
6299                     }
6300                 }
6301                 return;
6302             }
6303             return listen(element, eventName, options, fn, scope);
6304         },
6305         
6306         /**
6307          * Removes an event handler
6308          *
6309          * @param {String/HTMLElement}   element        The id or html element to remove the 
6310          *                             event from
6311          * @param {String}   eventName     The type of event
6312          * @param {Function} fn
6313          * @return {Boolean} True if a listener was actually removed
6314          */
6315         removeListener : function(element, eventName, fn){
6316             return stopListening(element, eventName, fn);
6317         },
6318         
6319         /**
6320          * Fires when the document is ready (before onload and before images are loaded). Can be 
6321          * accessed shorthanded Roo.onReady().
6322          * @param {Function} fn        The method the event invokes
6323          * @param {Object}   scope    An  object that becomes the scope of the handler
6324          * @param {boolean}  options
6325          */
6326         onDocumentReady : function(fn, scope, options){
6327             if(docReadyState){ // if it already fired
6328                 docReadyEvent.addListener(fn, scope, options);
6329                 docReadyEvent.fire();
6330                 docReadyEvent.clearListeners();
6331                 return;
6332             }
6333             if(!docReadyEvent){
6334                 initDocReady();
6335             }
6336             docReadyEvent.addListener(fn, scope, options);
6337         },
6338         
6339         /**
6340          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6341          * @param {Function} fn        The method the event invokes
6342          * @param {Object}   scope    An object that becomes the scope of the handler
6343          * @param {boolean}  options
6344          */
6345         onWindowResize : function(fn, scope, options){
6346             if(!resizeEvent){
6347                 resizeEvent = new Roo.util.Event();
6348                 resizeTask = new Roo.util.DelayedTask(function(){
6349                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6350                 });
6351                 E.on(window, "resize", function(){
6352                     if(Roo.isIE){
6353                         resizeTask.delay(50);
6354                     }else{
6355                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6356                     }
6357                 });
6358             }
6359             resizeEvent.addListener(fn, scope, options);
6360         },
6361
6362         /**
6363          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6364          * @param {Function} fn        The method the event invokes
6365          * @param {Object}   scope    An object that becomes the scope of the handler
6366          * @param {boolean}  options
6367          */
6368         onTextResize : function(fn, scope, options){
6369             if(!textEvent){
6370                 textEvent = new Roo.util.Event();
6371                 var textEl = new Roo.Element(document.createElement('div'));
6372                 textEl.dom.className = 'x-text-resize';
6373                 textEl.dom.innerHTML = 'X';
6374                 textEl.appendTo(document.body);
6375                 textSize = textEl.dom.offsetHeight;
6376                 setInterval(function(){
6377                     if(textEl.dom.offsetHeight != textSize){
6378                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6379                     }
6380                 }, this.textResizeInterval);
6381             }
6382             textEvent.addListener(fn, scope, options);
6383         },
6384
6385         /**
6386          * Removes the passed window resize listener.
6387          * @param {Function} fn        The method the event invokes
6388          * @param {Object}   scope    The scope of handler
6389          */
6390         removeResizeListener : function(fn, scope){
6391             if(resizeEvent){
6392                 resizeEvent.removeListener(fn, scope);
6393             }
6394         },
6395
6396         // private
6397         fireResize : function(){
6398             if(resizeEvent){
6399                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6400             }   
6401         },
6402         /**
6403          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6404          */
6405         ieDeferSrc : false,
6406         /**
6407          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6408          */
6409         textResizeInterval : 50
6410     };
6411     
6412     /**
6413      * Fix for doc tools
6414      * @scopeAlias pub=Roo.EventManager
6415      */
6416     
6417      /**
6418      * Appends an event handler to an element (shorthand for addListener)
6419      * @param {String/HTMLElement}   element        The html element or id to assign the
6420      * @param {String}   eventName The type of event to listen for
6421      * @param {Function} handler The method the event invokes
6422      * @param {Object}   scope (optional) The scope in which to execute the handler
6423      * function. The handler function's "this" context.
6424      * @param {Object}   options (optional) An object containing handler configuration
6425      * properties. This may contain any of the following properties:<ul>
6426      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6427      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6428      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6429      * <li>preventDefault {Boolean} True to prevent the default action</li>
6430      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6431      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6432      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6433      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6434      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6435      * by the specified number of milliseconds. If the event fires again within that time, the original
6436      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6437      * </ul><br>
6438      * <p>
6439      * <b>Combining Options</b><br>
6440      * Using the options argument, it is possible to combine different types of listeners:<br>
6441      * <br>
6442      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6443      * Code:<pre><code>
6444 el.on('click', this.onClick, this, {
6445     single: true,
6446     delay: 100,
6447     stopEvent : true,
6448     forumId: 4
6449 });</code></pre>
6450      * <p>
6451      * <b>Attaching multiple handlers in 1 call</b><br>
6452       * The method also allows for a single argument to be passed which is a config object containing properties
6453      * which specify multiple handlers.
6454      * <p>
6455      * Code:<pre><code>
6456 el.on({
6457     'click' : {
6458         fn: this.onClick
6459         scope: this,
6460         delay: 100
6461     },
6462     'mouseover' : {
6463         fn: this.onMouseOver
6464         scope: this
6465     },
6466     'mouseout' : {
6467         fn: this.onMouseOut
6468         scope: this
6469     }
6470 });</code></pre>
6471      * <p>
6472      * Or a shorthand syntax:<br>
6473      * Code:<pre><code>
6474 el.on({
6475     'click' : this.onClick,
6476     'mouseover' : this.onMouseOver,
6477     'mouseout' : this.onMouseOut
6478     scope: this
6479 });</code></pre>
6480      */
6481     pub.on = pub.addListener;
6482     pub.un = pub.removeListener;
6483
6484     pub.stoppedMouseDownEvent = new Roo.util.Event();
6485     return pub;
6486 }();
6487 /**
6488   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6489   * @param {Function} fn        The method the event invokes
6490   * @param {Object}   scope    An  object that becomes the scope of the handler
6491   * @param {boolean}  override If true, the obj passed in becomes
6492   *                             the execution scope of the listener
6493   * @member Roo
6494   * @method onReady
6495  */
6496 Roo.onReady = Roo.EventManager.onDocumentReady;
6497
6498 Roo.onReady(function(){
6499     var bd = Roo.get(document.body);
6500     if(!bd){ return; }
6501
6502     var cls = [
6503             Roo.isIE ? "roo-ie"
6504             : Roo.isGecko ? "roo-gecko"
6505             : Roo.isOpera ? "roo-opera"
6506             : Roo.isSafari ? "roo-safari" : ""];
6507
6508     if(Roo.isMac){
6509         cls.push("roo-mac");
6510     }
6511     if(Roo.isLinux){
6512         cls.push("roo-linux");
6513     }
6514     if(Roo.isBorderBox){
6515         cls.push('roo-border-box');
6516     }
6517     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6518         var p = bd.dom.parentNode;
6519         if(p){
6520             p.className += ' roo-strict';
6521         }
6522     }
6523     bd.addClass(cls.join(' '));
6524 });
6525
6526 /**
6527  * @class Roo.EventObject
6528  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6529  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6530  * Example:
6531  * <pre><code>
6532  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6533     e.preventDefault();
6534     var target = e.getTarget();
6535     ...
6536  }
6537  var myDiv = Roo.get("myDiv");
6538  myDiv.on("click", handleClick);
6539  //or
6540  Roo.EventManager.on("myDiv", 'click', handleClick);
6541  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6542  </code></pre>
6543  * @singleton
6544  */
6545 Roo.EventObject = function(){
6546     
6547     var E = Roo.lib.Event;
6548     
6549     // safari keypress events for special keys return bad keycodes
6550     var safariKeys = {
6551         63234 : 37, // left
6552         63235 : 39, // right
6553         63232 : 38, // up
6554         63233 : 40, // down
6555         63276 : 33, // page up
6556         63277 : 34, // page down
6557         63272 : 46, // delete
6558         63273 : 36, // home
6559         63275 : 35  // end
6560     };
6561
6562     // normalize button clicks
6563     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6564                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6565
6566     Roo.EventObjectImpl = function(e){
6567         if(e){
6568             this.setEvent(e.browserEvent || e);
6569         }
6570     };
6571     Roo.EventObjectImpl.prototype = {
6572         /**
6573          * Used to fix doc tools.
6574          * @scope Roo.EventObject.prototype
6575          */
6576             
6577
6578         
6579         
6580         /** The normal browser event */
6581         browserEvent : null,
6582         /** The button pressed in a mouse event */
6583         button : -1,
6584         /** True if the shift key was down during the event */
6585         shiftKey : false,
6586         /** True if the control key was down during the event */
6587         ctrlKey : false,
6588         /** True if the alt key was down during the event */
6589         altKey : false,
6590
6591         /** Key constant 
6592         * @type Number */
6593         BACKSPACE : 8,
6594         /** Key constant 
6595         * @type Number */
6596         TAB : 9,
6597         /** Key constant 
6598         * @type Number */
6599         RETURN : 13,
6600         /** Key constant 
6601         * @type Number */
6602         ENTER : 13,
6603         /** Key constant 
6604         * @type Number */
6605         SHIFT : 16,
6606         /** Key constant 
6607         * @type Number */
6608         CONTROL : 17,
6609         /** Key constant 
6610         * @type Number */
6611         ESC : 27,
6612         /** Key constant 
6613         * @type Number */
6614         SPACE : 32,
6615         /** Key constant 
6616         * @type Number */
6617         PAGEUP : 33,
6618         /** Key constant 
6619         * @type Number */
6620         PAGEDOWN : 34,
6621         /** Key constant 
6622         * @type Number */
6623         END : 35,
6624         /** Key constant 
6625         * @type Number */
6626         HOME : 36,
6627         /** Key constant 
6628         * @type Number */
6629         LEFT : 37,
6630         /** Key constant 
6631         * @type Number */
6632         UP : 38,
6633         /** Key constant 
6634         * @type Number */
6635         RIGHT : 39,
6636         /** Key constant 
6637         * @type Number */
6638         DOWN : 40,
6639         /** Key constant 
6640         * @type Number */
6641         DELETE : 46,
6642         /** Key constant 
6643         * @type Number */
6644         F5 : 116,
6645
6646            /** @private */
6647         setEvent : function(e){
6648             if(e == this || (e && e.browserEvent)){ // already wrapped
6649                 return e;
6650             }
6651             this.browserEvent = e;
6652             if(e){
6653                 // normalize buttons
6654                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6655                 if(e.type == 'click' && this.button == -1){
6656                     this.button = 0;
6657                 }
6658                 this.type = e.type;
6659                 this.shiftKey = e.shiftKey;
6660                 // mac metaKey behaves like ctrlKey
6661                 this.ctrlKey = e.ctrlKey || e.metaKey;
6662                 this.altKey = e.altKey;
6663                 // in getKey these will be normalized for the mac
6664                 this.keyCode = e.keyCode;
6665                 // keyup warnings on firefox.
6666                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6667                 // cache the target for the delayed and or buffered events
6668                 this.target = E.getTarget(e);
6669                 // same for XY
6670                 this.xy = E.getXY(e);
6671             }else{
6672                 this.button = -1;
6673                 this.shiftKey = false;
6674                 this.ctrlKey = false;
6675                 this.altKey = false;
6676                 this.keyCode = 0;
6677                 this.charCode =0;
6678                 this.target = null;
6679                 this.xy = [0, 0];
6680             }
6681             return this;
6682         },
6683
6684         /**
6685          * Stop the event (preventDefault and stopPropagation)
6686          */
6687         stopEvent : function(){
6688             if(this.browserEvent){
6689                 if(this.browserEvent.type == 'mousedown'){
6690                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6691                 }
6692                 E.stopEvent(this.browserEvent);
6693             }
6694         },
6695
6696         /**
6697          * Prevents the browsers default handling of the event.
6698          */
6699         preventDefault : function(){
6700             if(this.browserEvent){
6701                 E.preventDefault(this.browserEvent);
6702             }
6703         },
6704
6705         /** @private */
6706         isNavKeyPress : function(){
6707             var k = this.keyCode;
6708             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6709             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6710         },
6711
6712         isSpecialKey : function(){
6713             var k = this.keyCode;
6714             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6715             (k == 16) || (k == 17) ||
6716             (k >= 18 && k <= 20) ||
6717             (k >= 33 && k <= 35) ||
6718             (k >= 36 && k <= 39) ||
6719             (k >= 44 && k <= 45);
6720         },
6721         /**
6722          * Cancels bubbling of the event.
6723          */
6724         stopPropagation : function(){
6725             if(this.browserEvent){
6726                 if(this.type == 'mousedown'){
6727                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6728                 }
6729                 E.stopPropagation(this.browserEvent);
6730             }
6731         },
6732
6733         /**
6734          * Gets the key code for the event.
6735          * @return {Number}
6736          */
6737         getCharCode : function(){
6738             return this.charCode || this.keyCode;
6739         },
6740
6741         /**
6742          * Returns a normalized keyCode for the event.
6743          * @return {Number} The key code
6744          */
6745         getKey : function(){
6746             var k = this.keyCode || this.charCode;
6747             return Roo.isSafari ? (safariKeys[k] || k) : k;
6748         },
6749
6750         /**
6751          * Gets the x coordinate of the event.
6752          * @return {Number}
6753          */
6754         getPageX : function(){
6755             return this.xy[0];
6756         },
6757
6758         /**
6759          * Gets the y coordinate of the event.
6760          * @return {Number}
6761          */
6762         getPageY : function(){
6763             return this.xy[1];
6764         },
6765
6766         /**
6767          * Gets the time of the event.
6768          * @return {Number}
6769          */
6770         getTime : function(){
6771             if(this.browserEvent){
6772                 return E.getTime(this.browserEvent);
6773             }
6774             return null;
6775         },
6776
6777         /**
6778          * Gets the page coordinates of the event.
6779          * @return {Array} The xy values like [x, y]
6780          */
6781         getXY : function(){
6782             return this.xy;
6783         },
6784
6785         /**
6786          * Gets the target for the event.
6787          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6788          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6789                 search as a number or element (defaults to 10 || document.body)
6790          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6791          * @return {HTMLelement}
6792          */
6793         getTarget : function(selector, maxDepth, returnEl){
6794             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6795         },
6796         /**
6797          * Gets the related target.
6798          * @return {HTMLElement}
6799          */
6800         getRelatedTarget : function(){
6801             if(this.browserEvent){
6802                 return E.getRelatedTarget(this.browserEvent);
6803             }
6804             return null;
6805         },
6806
6807         /**
6808          * Normalizes mouse wheel delta across browsers
6809          * @return {Number} The delta
6810          */
6811         getWheelDelta : function(){
6812             var e = this.browserEvent;
6813             var delta = 0;
6814             if(e.wheelDelta){ /* IE/Opera. */
6815                 delta = e.wheelDelta/120;
6816             }else if(e.detail){ /* Mozilla case. */
6817                 delta = -e.detail/3;
6818             }
6819             return delta;
6820         },
6821
6822         /**
6823          * Returns true if the control, meta, shift or alt key was pressed during this event.
6824          * @return {Boolean}
6825          */
6826         hasModifier : function(){
6827             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6828         },
6829
6830         /**
6831          * Returns true if the target of this event equals el or is a child of el
6832          * @param {String/HTMLElement/Element} el
6833          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6834          * @return {Boolean}
6835          */
6836         within : function(el, related){
6837             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6838             return t && Roo.fly(el).contains(t);
6839         },
6840
6841         getPoint : function(){
6842             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6843         }
6844     };
6845
6846     return new Roo.EventObjectImpl();
6847 }();
6848             
6849     /*
6850  * Based on:
6851  * Ext JS Library 1.1.1
6852  * Copyright(c) 2006-2007, Ext JS, LLC.
6853  *
6854  * Originally Released Under LGPL - original licence link has changed is not relivant.
6855  *
6856  * Fork - LGPL
6857  * <script type="text/javascript">
6858  */
6859
6860  
6861 // was in Composite Element!??!?!
6862  
6863 (function(){
6864     var D = Roo.lib.Dom;
6865     var E = Roo.lib.Event;
6866     var A = Roo.lib.Anim;
6867
6868     // local style camelizing for speed
6869     var propCache = {};
6870     var camelRe = /(-[a-z])/gi;
6871     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6872     var view = document.defaultView;
6873
6874 /**
6875  * @class Roo.Element
6876  * Represents an Element in the DOM.<br><br>
6877  * Usage:<br>
6878 <pre><code>
6879 var el = Roo.get("my-div");
6880
6881 // or with getEl
6882 var el = getEl("my-div");
6883
6884 // or with a DOM element
6885 var el = Roo.get(myDivElement);
6886 </code></pre>
6887  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6888  * each call instead of constructing a new one.<br><br>
6889  * <b>Animations</b><br />
6890  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6891  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6892 <pre>
6893 Option    Default   Description
6894 --------- --------  ---------------------------------------------
6895 duration  .35       The duration of the animation in seconds
6896 easing    easeOut   The YUI easing method
6897 callback  none      A function to execute when the anim completes
6898 scope     this      The scope (this) of the callback function
6899 </pre>
6900 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6901 * manipulate the animation. Here's an example:
6902 <pre><code>
6903 var el = Roo.get("my-div");
6904
6905 // no animation
6906 el.setWidth(100);
6907
6908 // default animation
6909 el.setWidth(100, true);
6910
6911 // animation with some options set
6912 el.setWidth(100, {
6913     duration: 1,
6914     callback: this.foo,
6915     scope: this
6916 });
6917
6918 // using the "anim" property to get the Anim object
6919 var opt = {
6920     duration: 1,
6921     callback: this.foo,
6922     scope: this
6923 };
6924 el.setWidth(100, opt);
6925 ...
6926 if(opt.anim.isAnimated()){
6927     opt.anim.stop();
6928 }
6929 </code></pre>
6930 * <b> Composite (Collections of) Elements</b><br />
6931  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6932  * @constructor Create a new Element directly.
6933  * @param {String/HTMLElement} element
6934  * @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).
6935  */
6936     Roo.Element = function(element, forceNew){
6937         var dom = typeof element == "string" ?
6938                 document.getElementById(element) : element;
6939         if(!dom){ // invalid id/element
6940             return null;
6941         }
6942         var id = dom.id;
6943         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6944             return Roo.Element.cache[id];
6945         }
6946
6947         /**
6948          * The DOM element
6949          * @type HTMLElement
6950          */
6951         this.dom = dom;
6952
6953         /**
6954          * The DOM element ID
6955          * @type String
6956          */
6957         this.id = id || Roo.id(dom);
6958     };
6959
6960     var El = Roo.Element;
6961
6962     El.prototype = {
6963         /**
6964          * The element's default display mode  (defaults to "")
6965          * @type String
6966          */
6967         originalDisplay : "",
6968
6969         visibilityMode : 1,
6970         /**
6971          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6972          * @type String
6973          */
6974         defaultUnit : "px",
6975         /**
6976          * Sets the element's visibility mode. When setVisible() is called it
6977          * will use this to determine whether to set the visibility or the display property.
6978          * @param visMode Element.VISIBILITY or Element.DISPLAY
6979          * @return {Roo.Element} this
6980          */
6981         setVisibilityMode : function(visMode){
6982             this.visibilityMode = visMode;
6983             return this;
6984         },
6985         /**
6986          * Convenience method for setVisibilityMode(Element.DISPLAY)
6987          * @param {String} display (optional) What to set display to when visible
6988          * @return {Roo.Element} this
6989          */
6990         enableDisplayMode : function(display){
6991             this.setVisibilityMode(El.DISPLAY);
6992             if(typeof display != "undefined") this.originalDisplay = display;
6993             return this;
6994         },
6995
6996         /**
6997          * 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)
6998          * @param {String} selector The simple selector to test
6999          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7000                 search as a number or element (defaults to 10 || document.body)
7001          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7002          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7003          */
7004         findParent : function(simpleSelector, maxDepth, returnEl){
7005             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7006             maxDepth = maxDepth || 50;
7007             if(typeof maxDepth != "number"){
7008                 stopEl = Roo.getDom(maxDepth);
7009                 maxDepth = 10;
7010             }
7011             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7012                 if(dq.is(p, simpleSelector)){
7013                     return returnEl ? Roo.get(p) : p;
7014                 }
7015                 depth++;
7016                 p = p.parentNode;
7017             }
7018             return null;
7019         },
7020
7021
7022         /**
7023          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7024          * @param {String} selector The simple selector to test
7025          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7026                 search as a number or element (defaults to 10 || document.body)
7027          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7028          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7029          */
7030         findParentNode : function(simpleSelector, maxDepth, returnEl){
7031             var p = Roo.fly(this.dom.parentNode, '_internal');
7032             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7033         },
7034
7035         /**
7036          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7037          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7038          * @param {String} selector The simple selector to test
7039          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7040                 search as a number or element (defaults to 10 || document.body)
7041          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7042          */
7043         up : function(simpleSelector, maxDepth){
7044             return this.findParentNode(simpleSelector, maxDepth, true);
7045         },
7046
7047
7048
7049         /**
7050          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7051          * @param {String} selector The simple selector to test
7052          * @return {Boolean} True if this element matches the selector, else false
7053          */
7054         is : function(simpleSelector){
7055             return Roo.DomQuery.is(this.dom, simpleSelector);
7056         },
7057
7058         /**
7059          * Perform animation on this element.
7060          * @param {Object} args The YUI animation control args
7061          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7062          * @param {Function} onComplete (optional) Function to call when animation completes
7063          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7064          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7065          * @return {Roo.Element} this
7066          */
7067         animate : function(args, duration, onComplete, easing, animType){
7068             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7069             return this;
7070         },
7071
7072         /*
7073          * @private Internal animation call
7074          */
7075         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7076             animType = animType || 'run';
7077             opt = opt || {};
7078             var anim = Roo.lib.Anim[animType](
7079                 this.dom, args,
7080                 (opt.duration || defaultDur) || .35,
7081                 (opt.easing || defaultEase) || 'easeOut',
7082                 function(){
7083                     Roo.callback(cb, this);
7084                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7085                 },
7086                 this
7087             );
7088             opt.anim = anim;
7089             return anim;
7090         },
7091
7092         // private legacy anim prep
7093         preanim : function(a, i){
7094             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7095         },
7096
7097         /**
7098          * Removes worthless text nodes
7099          * @param {Boolean} forceReclean (optional) By default the element
7100          * keeps track if it has been cleaned already so
7101          * you can call this over and over. However, if you update the element and
7102          * need to force a reclean, you can pass true.
7103          */
7104         clean : function(forceReclean){
7105             if(this.isCleaned && forceReclean !== true){
7106                 return this;
7107             }
7108             var ns = /\S/;
7109             var d = this.dom, n = d.firstChild, ni = -1;
7110             while(n){
7111                 var nx = n.nextSibling;
7112                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7113                     d.removeChild(n);
7114                 }else{
7115                     n.nodeIndex = ++ni;
7116                 }
7117                 n = nx;
7118             }
7119             this.isCleaned = true;
7120             return this;
7121         },
7122
7123         // private
7124         calcOffsetsTo : function(el){
7125             el = Roo.get(el);
7126             var d = el.dom;
7127             var restorePos = false;
7128             if(el.getStyle('position') == 'static'){
7129                 el.position('relative');
7130                 restorePos = true;
7131             }
7132             var x = 0, y =0;
7133             var op = this.dom;
7134             while(op && op != d && op.tagName != 'HTML'){
7135                 x+= op.offsetLeft;
7136                 y+= op.offsetTop;
7137                 op = op.offsetParent;
7138             }
7139             if(restorePos){
7140                 el.position('static');
7141             }
7142             return [x, y];
7143         },
7144
7145         /**
7146          * Scrolls this element into view within the passed container.
7147          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7148          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7149          * @return {Roo.Element} this
7150          */
7151         scrollIntoView : function(container, hscroll){
7152             var c = Roo.getDom(container) || document.body;
7153             var el = this.dom;
7154
7155             var o = this.calcOffsetsTo(c),
7156                 l = o[0],
7157                 t = o[1],
7158                 b = t+el.offsetHeight,
7159                 r = l+el.offsetWidth;
7160
7161             var ch = c.clientHeight;
7162             var ct = parseInt(c.scrollTop, 10);
7163             var cl = parseInt(c.scrollLeft, 10);
7164             var cb = ct + ch;
7165             var cr = cl + c.clientWidth;
7166
7167             if(t < ct){
7168                 c.scrollTop = t;
7169             }else if(b > cb){
7170                 c.scrollTop = b-ch;
7171             }
7172
7173             if(hscroll !== false){
7174                 if(l < cl){
7175                     c.scrollLeft = l;
7176                 }else if(r > cr){
7177                     c.scrollLeft = r-c.clientWidth;
7178                 }
7179             }
7180             return this;
7181         },
7182
7183         // private
7184         scrollChildIntoView : function(child, hscroll){
7185             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7186         },
7187
7188         /**
7189          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7190          * the new height may not be available immediately.
7191          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7192          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7193          * @param {Function} onComplete (optional) Function to call when animation completes
7194          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7195          * @return {Roo.Element} this
7196          */
7197         autoHeight : function(animate, duration, onComplete, easing){
7198             var oldHeight = this.getHeight();
7199             this.clip();
7200             this.setHeight(1); // force clipping
7201             setTimeout(function(){
7202                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7203                 if(!animate){
7204                     this.setHeight(height);
7205                     this.unclip();
7206                     if(typeof onComplete == "function"){
7207                         onComplete();
7208                     }
7209                 }else{
7210                     this.setHeight(oldHeight); // restore original height
7211                     this.setHeight(height, animate, duration, function(){
7212                         this.unclip();
7213                         if(typeof onComplete == "function") onComplete();
7214                     }.createDelegate(this), easing);
7215                 }
7216             }.createDelegate(this), 0);
7217             return this;
7218         },
7219
7220         /**
7221          * Returns true if this element is an ancestor of the passed element
7222          * @param {HTMLElement/String} el The element to check
7223          * @return {Boolean} True if this element is an ancestor of el, else false
7224          */
7225         contains : function(el){
7226             if(!el){return false;}
7227             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7228         },
7229
7230         /**
7231          * Checks whether the element is currently visible using both visibility and display properties.
7232          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7233          * @return {Boolean} True if the element is currently visible, else false
7234          */
7235         isVisible : function(deep) {
7236             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7237             if(deep !== true || !vis){
7238                 return vis;
7239             }
7240             var p = this.dom.parentNode;
7241             while(p && p.tagName.toLowerCase() != "body"){
7242                 if(!Roo.fly(p, '_isVisible').isVisible()){
7243                     return false;
7244                 }
7245                 p = p.parentNode;
7246             }
7247             return true;
7248         },
7249
7250         /**
7251          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7252          * @param {String} selector The CSS selector
7253          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7254          * @return {CompositeElement/CompositeElementLite} The composite element
7255          */
7256         select : function(selector, unique){
7257             return El.select(selector, unique, this.dom);
7258         },
7259
7260         /**
7261          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7262          * @param {String} selector The CSS selector
7263          * @return {Array} An array of the matched nodes
7264          */
7265         query : function(selector, unique){
7266             return Roo.DomQuery.select(selector, this.dom);
7267         },
7268
7269         /**
7270          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7271          * @param {String} selector The CSS selector
7272          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7273          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7274          */
7275         child : function(selector, returnDom){
7276             var n = Roo.DomQuery.selectNode(selector, this.dom);
7277             return returnDom ? n : Roo.get(n);
7278         },
7279
7280         /**
7281          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7282          * @param {String} selector The CSS selector
7283          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7284          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7285          */
7286         down : function(selector, returnDom){
7287             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7288             return returnDom ? n : Roo.get(n);
7289         },
7290
7291         /**
7292          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7293          * @param {String} group The group the DD object is member of
7294          * @param {Object} config The DD config object
7295          * @param {Object} overrides An object containing methods to override/implement on the DD object
7296          * @return {Roo.dd.DD} The DD object
7297          */
7298         initDD : function(group, config, overrides){
7299             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7300             return Roo.apply(dd, overrides);
7301         },
7302
7303         /**
7304          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7305          * @param {String} group The group the DDProxy object is member of
7306          * @param {Object} config The DDProxy config object
7307          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7308          * @return {Roo.dd.DDProxy} The DDProxy object
7309          */
7310         initDDProxy : function(group, config, overrides){
7311             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7312             return Roo.apply(dd, overrides);
7313         },
7314
7315         /**
7316          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7317          * @param {String} group The group the DDTarget object is member of
7318          * @param {Object} config The DDTarget config object
7319          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7320          * @return {Roo.dd.DDTarget} The DDTarget object
7321          */
7322         initDDTarget : function(group, config, overrides){
7323             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7324             return Roo.apply(dd, overrides);
7325         },
7326
7327         /**
7328          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7329          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7330          * @param {Boolean} visible Whether the element is visible
7331          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7332          * @return {Roo.Element} this
7333          */
7334          setVisible : function(visible, animate){
7335             if(!animate || !A){
7336                 if(this.visibilityMode == El.DISPLAY){
7337                     this.setDisplayed(visible);
7338                 }else{
7339                     this.fixDisplay();
7340                     this.dom.style.visibility = visible ? "visible" : "hidden";
7341                 }
7342             }else{
7343                 // closure for composites
7344                 var dom = this.dom;
7345                 var visMode = this.visibilityMode;
7346                 if(visible){
7347                     this.setOpacity(.01);
7348                     this.setVisible(true);
7349                 }
7350                 this.anim({opacity: { to: (visible?1:0) }},
7351                       this.preanim(arguments, 1),
7352                       null, .35, 'easeIn', function(){
7353                          if(!visible){
7354                              if(visMode == El.DISPLAY){
7355                                  dom.style.display = "none";
7356                              }else{
7357                                  dom.style.visibility = "hidden";
7358                              }
7359                              Roo.get(dom).setOpacity(1);
7360                          }
7361                      });
7362             }
7363             return this;
7364         },
7365
7366         /**
7367          * Returns true if display is not "none"
7368          * @return {Boolean}
7369          */
7370         isDisplayed : function() {
7371             return this.getStyle("display") != "none";
7372         },
7373
7374         /**
7375          * Toggles the element's visibility or display, depending on visibility mode.
7376          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7377          * @return {Roo.Element} this
7378          */
7379         toggle : function(animate){
7380             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7381             return this;
7382         },
7383
7384         /**
7385          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7386          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7387          * @return {Roo.Element} this
7388          */
7389         setDisplayed : function(value) {
7390             if(typeof value == "boolean"){
7391                value = value ? this.originalDisplay : "none";
7392             }
7393             this.setStyle("display", value);
7394             return this;
7395         },
7396
7397         /**
7398          * Tries to focus the element. Any exceptions are caught and ignored.
7399          * @return {Roo.Element} this
7400          */
7401         focus : function() {
7402             try{
7403                 this.dom.focus();
7404             }catch(e){}
7405             return this;
7406         },
7407
7408         /**
7409          * Tries to blur the element. Any exceptions are caught and ignored.
7410          * @return {Roo.Element} this
7411          */
7412         blur : function() {
7413             try{
7414                 this.dom.blur();
7415             }catch(e){}
7416             return this;
7417         },
7418
7419         /**
7420          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7421          * @param {String/Array} className The CSS class to add, or an array of classes
7422          * @return {Roo.Element} this
7423          */
7424         addClass : function(className){
7425             if(className instanceof Array){
7426                 for(var i = 0, len = className.length; i < len; i++) {
7427                     this.addClass(className[i]);
7428                 }
7429             }else{
7430                 if(className && !this.hasClass(className)){
7431                     this.dom.className = this.dom.className + " " + className;
7432                 }
7433             }
7434             return this;
7435         },
7436
7437         /**
7438          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7439          * @param {String/Array} className The CSS class to add, or an array of classes
7440          * @return {Roo.Element} this
7441          */
7442         radioClass : function(className){
7443             var siblings = this.dom.parentNode.childNodes;
7444             for(var i = 0; i < siblings.length; i++) {
7445                 var s = siblings[i];
7446                 if(s.nodeType == 1){
7447                     Roo.get(s).removeClass(className);
7448                 }
7449             }
7450             this.addClass(className);
7451             return this;
7452         },
7453
7454         /**
7455          * Removes one or more CSS classes from the element.
7456          * @param {String/Array} className The CSS class to remove, or an array of classes
7457          * @return {Roo.Element} this
7458          */
7459         removeClass : function(className){
7460             if(!className || !this.dom.className){
7461                 return this;
7462             }
7463             if(className instanceof Array){
7464                 for(var i = 0, len = className.length; i < len; i++) {
7465                     this.removeClass(className[i]);
7466                 }
7467             }else{
7468                 if(this.hasClass(className)){
7469                     var re = this.classReCache[className];
7470                     if (!re) {
7471                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7472                        this.classReCache[className] = re;
7473                     }
7474                     this.dom.className =
7475                         this.dom.className.replace(re, " ");
7476                 }
7477             }
7478             return this;
7479         },
7480
7481         // private
7482         classReCache: {},
7483
7484         /**
7485          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7486          * @param {String} className The CSS class to toggle
7487          * @return {Roo.Element} this
7488          */
7489         toggleClass : function(className){
7490             if(this.hasClass(className)){
7491                 this.removeClass(className);
7492             }else{
7493                 this.addClass(className);
7494             }
7495             return this;
7496         },
7497
7498         /**
7499          * Checks if the specified CSS class exists on this element's DOM node.
7500          * @param {String} className The CSS class to check for
7501          * @return {Boolean} True if the class exists, else false
7502          */
7503         hasClass : function(className){
7504             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7505         },
7506
7507         /**
7508          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7509          * @param {String} oldClassName The CSS class to replace
7510          * @param {String} newClassName The replacement CSS class
7511          * @return {Roo.Element} this
7512          */
7513         replaceClass : function(oldClassName, newClassName){
7514             this.removeClass(oldClassName);
7515             this.addClass(newClassName);
7516             return this;
7517         },
7518
7519         /**
7520          * Returns an object with properties matching the styles requested.
7521          * For example, el.getStyles('color', 'font-size', 'width') might return
7522          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7523          * @param {String} style1 A style name
7524          * @param {String} style2 A style name
7525          * @param {String} etc.
7526          * @return {Object} The style object
7527          */
7528         getStyles : function(){
7529             var a = arguments, len = a.length, r = {};
7530             for(var i = 0; i < len; i++){
7531                 r[a[i]] = this.getStyle(a[i]);
7532             }
7533             return r;
7534         },
7535
7536         /**
7537          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7538          * @param {String} property The style property whose value is returned.
7539          * @return {String} The current value of the style property for this element.
7540          */
7541         getStyle : function(){
7542             return view && view.getComputedStyle ?
7543                 function(prop){
7544                     var el = this.dom, v, cs, camel;
7545                     if(prop == 'float'){
7546                         prop = "cssFloat";
7547                     }
7548                     if(el.style && (v = el.style[prop])){
7549                         return v;
7550                     }
7551                     if(cs = view.getComputedStyle(el, "")){
7552                         if(!(camel = propCache[prop])){
7553                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7554                         }
7555                         return cs[camel];
7556                     }
7557                     return null;
7558                 } :
7559                 function(prop){
7560                     var el = this.dom, v, cs, camel;
7561                     if(prop == 'opacity'){
7562                         if(typeof el.style.filter == 'string'){
7563                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7564                             if(m){
7565                                 var fv = parseFloat(m[1]);
7566                                 if(!isNaN(fv)){
7567                                     return fv ? fv / 100 : 0;
7568                                 }
7569                             }
7570                         }
7571                         return 1;
7572                     }else if(prop == 'float'){
7573                         prop = "styleFloat";
7574                     }
7575                     if(!(camel = propCache[prop])){
7576                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7577                     }
7578                     if(v = el.style[camel]){
7579                         return v;
7580                     }
7581                     if(cs = el.currentStyle){
7582                         return cs[camel];
7583                     }
7584                     return null;
7585                 };
7586         }(),
7587
7588         /**
7589          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7590          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7591          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7592          * @return {Roo.Element} this
7593          */
7594         setStyle : function(prop, value){
7595             if(typeof prop == "string"){
7596                 
7597                 if (prop == 'float') {
7598                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7599                     return this;
7600                 }
7601                 
7602                 var camel;
7603                 if(!(camel = propCache[prop])){
7604                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7605                 }
7606                 
7607                 if(camel == 'opacity') {
7608                     this.setOpacity(value);
7609                 }else{
7610                     this.dom.style[camel] = value;
7611                 }
7612             }else{
7613                 for(var style in prop){
7614                     if(typeof prop[style] != "function"){
7615                        this.setStyle(style, prop[style]);
7616                     }
7617                 }
7618             }
7619             return this;
7620         },
7621
7622         /**
7623          * More flexible version of {@link #setStyle} for setting style properties.
7624          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7625          * a function which returns such a specification.
7626          * @return {Roo.Element} this
7627          */
7628         applyStyles : function(style){
7629             Roo.DomHelper.applyStyles(this.dom, style);
7630             return this;
7631         },
7632
7633         /**
7634           * 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).
7635           * @return {Number} The X position of the element
7636           */
7637         getX : function(){
7638             return D.getX(this.dom);
7639         },
7640
7641         /**
7642           * 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).
7643           * @return {Number} The Y position of the element
7644           */
7645         getY : function(){
7646             return D.getY(this.dom);
7647         },
7648
7649         /**
7650           * 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).
7651           * @return {Array} The XY position of the element
7652           */
7653         getXY : function(){
7654             return D.getXY(this.dom);
7655         },
7656
7657         /**
7658          * 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).
7659          * @param {Number} The X position of the element
7660          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7661          * @return {Roo.Element} this
7662          */
7663         setX : function(x, animate){
7664             if(!animate || !A){
7665                 D.setX(this.dom, x);
7666             }else{
7667                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7668             }
7669             return this;
7670         },
7671
7672         /**
7673          * 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).
7674          * @param {Number} The Y position of the element
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         setY : function(y, animate){
7679             if(!animate || !A){
7680                 D.setY(this.dom, y);
7681             }else{
7682                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7683             }
7684             return this;
7685         },
7686
7687         /**
7688          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7689          * @param {String} left The left CSS property value
7690          * @return {Roo.Element} this
7691          */
7692         setLeft : function(left){
7693             this.setStyle("left", this.addUnits(left));
7694             return this;
7695         },
7696
7697         /**
7698          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7699          * @param {String} top The top CSS property value
7700          * @return {Roo.Element} this
7701          */
7702         setTop : function(top){
7703             this.setStyle("top", this.addUnits(top));
7704             return this;
7705         },
7706
7707         /**
7708          * Sets the element's CSS right style.
7709          * @param {String} right The right CSS property value
7710          * @return {Roo.Element} this
7711          */
7712         setRight : function(right){
7713             this.setStyle("right", this.addUnits(right));
7714             return this;
7715         },
7716
7717         /**
7718          * Sets the element's CSS bottom style.
7719          * @param {String} bottom The bottom CSS property value
7720          * @return {Roo.Element} this
7721          */
7722         setBottom : function(bottom){
7723             this.setStyle("bottom", this.addUnits(bottom));
7724             return this;
7725         },
7726
7727         /**
7728          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7729          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7730          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
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         setXY : function(pos, animate){
7735             if(!animate || !A){
7736                 D.setXY(this.dom, pos);
7737             }else{
7738                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7739             }
7740             return this;
7741         },
7742
7743         /**
7744          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7745          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7746          * @param {Number} x X value for new position (coordinates are page-based)
7747          * @param {Number} y Y value for new position (coordinates are page-based)
7748          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7749          * @return {Roo.Element} this
7750          */
7751         setLocation : function(x, y, animate){
7752             this.setXY([x, y], this.preanim(arguments, 2));
7753             return this;
7754         },
7755
7756         /**
7757          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7758          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7759          * @param {Number} x X value for new position (coordinates are page-based)
7760          * @param {Number} y Y value for new position (coordinates are page-based)
7761          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7762          * @return {Roo.Element} this
7763          */
7764         moveTo : function(x, y, animate){
7765             this.setXY([x, y], this.preanim(arguments, 2));
7766             return this;
7767         },
7768
7769         /**
7770          * Returns the region of the given element.
7771          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7772          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7773          */
7774         getRegion : function(){
7775             return D.getRegion(this.dom);
7776         },
7777
7778         /**
7779          * Returns the offset height of the element
7780          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7781          * @return {Number} The element's height
7782          */
7783         getHeight : function(contentHeight){
7784             var h = this.dom.offsetHeight || 0;
7785             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7786         },
7787
7788         /**
7789          * Returns the offset width of the element
7790          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7791          * @return {Number} The element's width
7792          */
7793         getWidth : function(contentWidth){
7794             var w = this.dom.offsetWidth || 0;
7795             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7796         },
7797
7798         /**
7799          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7800          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7801          * if a height has not been set using CSS.
7802          * @return {Number}
7803          */
7804         getComputedHeight : function(){
7805             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7806             if(!h){
7807                 h = parseInt(this.getStyle('height'), 10) || 0;
7808                 if(!this.isBorderBox()){
7809                     h += this.getFrameWidth('tb');
7810                 }
7811             }
7812             return h;
7813         },
7814
7815         /**
7816          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7817          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7818          * if a width has not been set using CSS.
7819          * @return {Number}
7820          */
7821         getComputedWidth : function(){
7822             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7823             if(!w){
7824                 w = parseInt(this.getStyle('width'), 10) || 0;
7825                 if(!this.isBorderBox()){
7826                     w += this.getFrameWidth('lr');
7827                 }
7828             }
7829             return w;
7830         },
7831
7832         /**
7833          * Returns the size of the element.
7834          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7835          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7836          */
7837         getSize : function(contentSize){
7838             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7839         },
7840
7841         /**
7842          * Returns the width and height of the viewport.
7843          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7844          */
7845         getViewSize : function(){
7846             var d = this.dom, doc = document, aw = 0, ah = 0;
7847             if(d == doc || d == doc.body){
7848                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7849             }else{
7850                 return {
7851                     width : d.clientWidth,
7852                     height: d.clientHeight
7853                 };
7854             }
7855         },
7856
7857         /**
7858          * Returns the value of the "value" attribute
7859          * @param {Boolean} asNumber true to parse the value as a number
7860          * @return {String/Number}
7861          */
7862         getValue : function(asNumber){
7863             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7864         },
7865
7866         // private
7867         adjustWidth : function(width){
7868             if(typeof width == "number"){
7869                 if(this.autoBoxAdjust && !this.isBorderBox()){
7870                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7871                 }
7872                 if(width < 0){
7873                     width = 0;
7874                 }
7875             }
7876             return width;
7877         },
7878
7879         // private
7880         adjustHeight : function(height){
7881             if(typeof height == "number"){
7882                if(this.autoBoxAdjust && !this.isBorderBox()){
7883                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7884                }
7885                if(height < 0){
7886                    height = 0;
7887                }
7888             }
7889             return height;
7890         },
7891
7892         /**
7893          * Set the width of the element
7894          * @param {Number} width The new width
7895          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7896          * @return {Roo.Element} this
7897          */
7898         setWidth : function(width, animate){
7899             width = this.adjustWidth(width);
7900             if(!animate || !A){
7901                 this.dom.style.width = this.addUnits(width);
7902             }else{
7903                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7904             }
7905             return this;
7906         },
7907
7908         /**
7909          * Set the height of the element
7910          * @param {Number} height The new height
7911          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7912          * @return {Roo.Element} this
7913          */
7914          setHeight : function(height, animate){
7915             height = this.adjustHeight(height);
7916             if(!animate || !A){
7917                 this.dom.style.height = this.addUnits(height);
7918             }else{
7919                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7920             }
7921             return this;
7922         },
7923
7924         /**
7925          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7926          * @param {Number} width The new width
7927          * @param {Number} height The new height
7928          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7929          * @return {Roo.Element} this
7930          */
7931          setSize : function(width, height, animate){
7932             if(typeof width == "object"){ // in case of object from getSize()
7933                 height = width.height; width = width.width;
7934             }
7935             width = this.adjustWidth(width); height = this.adjustHeight(height);
7936             if(!animate || !A){
7937                 this.dom.style.width = this.addUnits(width);
7938                 this.dom.style.height = this.addUnits(height);
7939             }else{
7940                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7941             }
7942             return this;
7943         },
7944
7945         /**
7946          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7947          * @param {Number} x X value for new position (coordinates are page-based)
7948          * @param {Number} y Y value for new position (coordinates are page-based)
7949          * @param {Number} width The new width
7950          * @param {Number} height The new height
7951          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7952          * @return {Roo.Element} this
7953          */
7954         setBounds : function(x, y, width, height, animate){
7955             if(!animate || !A){
7956                 this.setSize(width, height);
7957                 this.setLocation(x, y);
7958             }else{
7959                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7960                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7961                               this.preanim(arguments, 4), 'motion');
7962             }
7963             return this;
7964         },
7965
7966         /**
7967          * 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.
7968          * @param {Roo.lib.Region} region The region to fill
7969          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7970          * @return {Roo.Element} this
7971          */
7972         setRegion : function(region, animate){
7973             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7974             return this;
7975         },
7976
7977         /**
7978          * Appends an event handler
7979          *
7980          * @param {String}   eventName     The type of event to append
7981          * @param {Function} fn        The method the event invokes
7982          * @param {Object} scope       (optional) The scope (this object) of the fn
7983          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7984          */
7985         addListener : function(eventName, fn, scope, options){
7986             if (this.dom) {
7987                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7988             }
7989         },
7990
7991         /**
7992          * Removes an event handler from this element
7993          * @param {String} eventName the type of event to remove
7994          * @param {Function} fn the method the event invokes
7995          * @return {Roo.Element} this
7996          */
7997         removeListener : function(eventName, fn){
7998             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7999             return this;
8000         },
8001
8002         /**
8003          * Removes all previous added listeners from this element
8004          * @return {Roo.Element} this
8005          */
8006         removeAllListeners : function(){
8007             E.purgeElement(this.dom);
8008             return this;
8009         },
8010
8011         relayEvent : function(eventName, observable){
8012             this.on(eventName, function(e){
8013                 observable.fireEvent(eventName, e);
8014             });
8015         },
8016
8017         /**
8018          * Set the opacity of the element
8019          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8020          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8021          * @return {Roo.Element} this
8022          */
8023          setOpacity : function(opacity, animate){
8024             if(!animate || !A){
8025                 var s = this.dom.style;
8026                 if(Roo.isIE){
8027                     s.zoom = 1;
8028                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8029                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8030                 }else{
8031                     s.opacity = opacity;
8032                 }
8033             }else{
8034                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8035             }
8036             return this;
8037         },
8038
8039         /**
8040          * Gets the left X coordinate
8041          * @param {Boolean} local True to get the local css position instead of page coordinate
8042          * @return {Number}
8043          */
8044         getLeft : function(local){
8045             if(!local){
8046                 return this.getX();
8047             }else{
8048                 return parseInt(this.getStyle("left"), 10) || 0;
8049             }
8050         },
8051
8052         /**
8053          * Gets the right X coordinate of the element (element X position + element width)
8054          * @param {Boolean} local True to get the local css position instead of page coordinate
8055          * @return {Number}
8056          */
8057         getRight : function(local){
8058             if(!local){
8059                 return this.getX() + this.getWidth();
8060             }else{
8061                 return (this.getLeft(true) + this.getWidth()) || 0;
8062             }
8063         },
8064
8065         /**
8066          * Gets the top Y coordinate
8067          * @param {Boolean} local True to get the local css position instead of page coordinate
8068          * @return {Number}
8069          */
8070         getTop : function(local) {
8071             if(!local){
8072                 return this.getY();
8073             }else{
8074                 return parseInt(this.getStyle("top"), 10) || 0;
8075             }
8076         },
8077
8078         /**
8079          * Gets the bottom Y coordinate of the element (element Y position + element height)
8080          * @param {Boolean} local True to get the local css position instead of page coordinate
8081          * @return {Number}
8082          */
8083         getBottom : function(local){
8084             if(!local){
8085                 return this.getY() + this.getHeight();
8086             }else{
8087                 return (this.getTop(true) + this.getHeight()) || 0;
8088             }
8089         },
8090
8091         /**
8092         * Initializes positioning on this element. If a desired position is not passed, it will make the
8093         * the element positioned relative IF it is not already positioned.
8094         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8095         * @param {Number} zIndex (optional) The zIndex to apply
8096         * @param {Number} x (optional) Set the page X position
8097         * @param {Number} y (optional) Set the page Y position
8098         */
8099         position : function(pos, zIndex, x, y){
8100             if(!pos){
8101                if(this.getStyle('position') == 'static'){
8102                    this.setStyle('position', 'relative');
8103                }
8104             }else{
8105                 this.setStyle("position", pos);
8106             }
8107             if(zIndex){
8108                 this.setStyle("z-index", zIndex);
8109             }
8110             if(x !== undefined && y !== undefined){
8111                 this.setXY([x, y]);
8112             }else if(x !== undefined){
8113                 this.setX(x);
8114             }else if(y !== undefined){
8115                 this.setY(y);
8116             }
8117         },
8118
8119         /**
8120         * Clear positioning back to the default when the document was loaded
8121         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8122         * @return {Roo.Element} this
8123          */
8124         clearPositioning : function(value){
8125             value = value ||'';
8126             this.setStyle({
8127                 "left": value,
8128                 "right": value,
8129                 "top": value,
8130                 "bottom": value,
8131                 "z-index": "",
8132                 "position" : "static"
8133             });
8134             return this;
8135         },
8136
8137         /**
8138         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8139         * snapshot before performing an update and then restoring the element.
8140         * @return {Object}
8141         */
8142         getPositioning : function(){
8143             var l = this.getStyle("left");
8144             var t = this.getStyle("top");
8145             return {
8146                 "position" : this.getStyle("position"),
8147                 "left" : l,
8148                 "right" : l ? "" : this.getStyle("right"),
8149                 "top" : t,
8150                 "bottom" : t ? "" : this.getStyle("bottom"),
8151                 "z-index" : this.getStyle("z-index")
8152             };
8153         },
8154
8155         /**
8156          * Gets the width of the border(s) for the specified side(s)
8157          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8158          * passing lr would get the border (l)eft width + the border (r)ight width.
8159          * @return {Number} The width of the sides passed added together
8160          */
8161         getBorderWidth : function(side){
8162             return this.addStyles(side, El.borders);
8163         },
8164
8165         /**
8166          * Gets the width of the padding(s) for the specified side(s)
8167          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8168          * passing lr would get the padding (l)eft + the padding (r)ight.
8169          * @return {Number} The padding of the sides passed added together
8170          */
8171         getPadding : function(side){
8172             return this.addStyles(side, El.paddings);
8173         },
8174
8175         /**
8176         * Set positioning with an object returned by getPositioning().
8177         * @param {Object} posCfg
8178         * @return {Roo.Element} this
8179          */
8180         setPositioning : function(pc){
8181             this.applyStyles(pc);
8182             if(pc.right == "auto"){
8183                 this.dom.style.right = "";
8184             }
8185             if(pc.bottom == "auto"){
8186                 this.dom.style.bottom = "";
8187             }
8188             return this;
8189         },
8190
8191         // private
8192         fixDisplay : function(){
8193             if(this.getStyle("display") == "none"){
8194                 this.setStyle("visibility", "hidden");
8195                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8196                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8197                     this.setStyle("display", "block");
8198                 }
8199             }
8200         },
8201
8202         /**
8203          * Quick set left and top adding default units
8204          * @param {String} left The left CSS property value
8205          * @param {String} top The top CSS property value
8206          * @return {Roo.Element} this
8207          */
8208          setLeftTop : function(left, top){
8209             this.dom.style.left = this.addUnits(left);
8210             this.dom.style.top = this.addUnits(top);
8211             return this;
8212         },
8213
8214         /**
8215          * Move this element relative to its current position.
8216          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8217          * @param {Number} distance How far to move the element in pixels
8218          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8219          * @return {Roo.Element} this
8220          */
8221          move : function(direction, distance, animate){
8222             var xy = this.getXY();
8223             direction = direction.toLowerCase();
8224             switch(direction){
8225                 case "l":
8226                 case "left":
8227                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8228                     break;
8229                case "r":
8230                case "right":
8231                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8232                     break;
8233                case "t":
8234                case "top":
8235                case "up":
8236                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8237                     break;
8238                case "b":
8239                case "bottom":
8240                case "down":
8241                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8242                     break;
8243             }
8244             return this;
8245         },
8246
8247         /**
8248          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8249          * @return {Roo.Element} this
8250          */
8251         clip : function(){
8252             if(!this.isClipped){
8253                this.isClipped = true;
8254                this.originalClip = {
8255                    "o": this.getStyle("overflow"),
8256                    "x": this.getStyle("overflow-x"),
8257                    "y": this.getStyle("overflow-y")
8258                };
8259                this.setStyle("overflow", "hidden");
8260                this.setStyle("overflow-x", "hidden");
8261                this.setStyle("overflow-y", "hidden");
8262             }
8263             return this;
8264         },
8265
8266         /**
8267          *  Return clipping (overflow) to original clipping before clip() was called
8268          * @return {Roo.Element} this
8269          */
8270         unclip : function(){
8271             if(this.isClipped){
8272                 this.isClipped = false;
8273                 var o = this.originalClip;
8274                 if(o.o){this.setStyle("overflow", o.o);}
8275                 if(o.x){this.setStyle("overflow-x", o.x);}
8276                 if(o.y){this.setStyle("overflow-y", o.y);}
8277             }
8278             return this;
8279         },
8280
8281
8282         /**
8283          * Gets the x,y coordinates specified by the anchor position on the element.
8284          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8285          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8286          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8287          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8288          * @return {Array} [x, y] An array containing the element's x and y coordinates
8289          */
8290         getAnchorXY : function(anchor, local, s){
8291             //Passing a different size is useful for pre-calculating anchors,
8292             //especially for anchored animations that change the el size.
8293
8294             var w, h, vp = false;
8295             if(!s){
8296                 var d = this.dom;
8297                 if(d == document.body || d == document){
8298                     vp = true;
8299                     w = D.getViewWidth(); h = D.getViewHeight();
8300                 }else{
8301                     w = this.getWidth(); h = this.getHeight();
8302                 }
8303             }else{
8304                 w = s.width;  h = s.height;
8305             }
8306             var x = 0, y = 0, r = Math.round;
8307             switch((anchor || "tl").toLowerCase()){
8308                 case "c":
8309                     x = r(w*.5);
8310                     y = r(h*.5);
8311                 break;
8312                 case "t":
8313                     x = r(w*.5);
8314                     y = 0;
8315                 break;
8316                 case "l":
8317                     x = 0;
8318                     y = r(h*.5);
8319                 break;
8320                 case "r":
8321                     x = w;
8322                     y = r(h*.5);
8323                 break;
8324                 case "b":
8325                     x = r(w*.5);
8326                     y = h;
8327                 break;
8328                 case "tl":
8329                     x = 0;
8330                     y = 0;
8331                 break;
8332                 case "bl":
8333                     x = 0;
8334                     y = h;
8335                 break;
8336                 case "br":
8337                     x = w;
8338                     y = h;
8339                 break;
8340                 case "tr":
8341                     x = w;
8342                     y = 0;
8343                 break;
8344             }
8345             if(local === true){
8346                 return [x, y];
8347             }
8348             if(vp){
8349                 var sc = this.getScroll();
8350                 return [x + sc.left, y + sc.top];
8351             }
8352             //Add the element's offset xy
8353             var o = this.getXY();
8354             return [x+o[0], y+o[1]];
8355         },
8356
8357         /**
8358          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8359          * supported position values.
8360          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8361          * @param {String} position The position to align to.
8362          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8363          * @return {Array} [x, y]
8364          */
8365         getAlignToXY : function(el, p, o){
8366             el = Roo.get(el);
8367             var d = this.dom;
8368             if(!el.dom){
8369                 throw "Element.alignTo with an element that doesn't exist";
8370             }
8371             var c = false; //constrain to viewport
8372             var p1 = "", p2 = "";
8373             o = o || [0,0];
8374
8375             if(!p){
8376                 p = "tl-bl";
8377             }else if(p == "?"){
8378                 p = "tl-bl?";
8379             }else if(p.indexOf("-") == -1){
8380                 p = "tl-" + p;
8381             }
8382             p = p.toLowerCase();
8383             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8384             if(!m){
8385                throw "Element.alignTo with an invalid alignment " + p;
8386             }
8387             p1 = m[1]; p2 = m[2]; c = !!m[3];
8388
8389             //Subtract the aligned el's internal xy from the target's offset xy
8390             //plus custom offset to get the aligned el's new offset xy
8391             var a1 = this.getAnchorXY(p1, true);
8392             var a2 = el.getAnchorXY(p2, false);
8393             var x = a2[0] - a1[0] + o[0];
8394             var y = a2[1] - a1[1] + o[1];
8395             if(c){
8396                 //constrain the aligned el to viewport if necessary
8397                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8398                 // 5px of margin for ie
8399                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8400
8401                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8402                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8403                 //otherwise swap the aligned el to the opposite border of the target.
8404                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8405                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8406                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8407                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8408
8409                var doc = document;
8410                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8411                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8412
8413                if((x+w) > dw + scrollX){
8414                     x = swapX ? r.left-w : dw+scrollX-w;
8415                 }
8416                if(x < scrollX){
8417                    x = swapX ? r.right : scrollX;
8418                }
8419                if((y+h) > dh + scrollY){
8420                     y = swapY ? r.top-h : dh+scrollY-h;
8421                 }
8422                if (y < scrollY){
8423                    y = swapY ? r.bottom : scrollY;
8424                }
8425             }
8426             return [x,y];
8427         },
8428
8429         // private
8430         getConstrainToXY : function(){
8431             var os = {top:0, left:0, bottom:0, right: 0};
8432
8433             return function(el, local, offsets, proposedXY){
8434                 el = Roo.get(el);
8435                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8436
8437                 var vw, vh, vx = 0, vy = 0;
8438                 if(el.dom == document.body || el.dom == document){
8439                     vw = Roo.lib.Dom.getViewWidth();
8440                     vh = Roo.lib.Dom.getViewHeight();
8441                 }else{
8442                     vw = el.dom.clientWidth;
8443                     vh = el.dom.clientHeight;
8444                     if(!local){
8445                         var vxy = el.getXY();
8446                         vx = vxy[0];
8447                         vy = vxy[1];
8448                     }
8449                 }
8450
8451                 var s = el.getScroll();
8452
8453                 vx += offsets.left + s.left;
8454                 vy += offsets.top + s.top;
8455
8456                 vw -= offsets.right;
8457                 vh -= offsets.bottom;
8458
8459                 var vr = vx+vw;
8460                 var vb = vy+vh;
8461
8462                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8463                 var x = xy[0], y = xy[1];
8464                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8465
8466                 // only move it if it needs it
8467                 var moved = false;
8468
8469                 // first validate right/bottom
8470                 if((x + w) > vr){
8471                     x = vr - w;
8472                     moved = true;
8473                 }
8474                 if((y + h) > vb){
8475                     y = vb - h;
8476                     moved = true;
8477                 }
8478                 // then make sure top/left isn't negative
8479                 if(x < vx){
8480                     x = vx;
8481                     moved = true;
8482                 }
8483                 if(y < vy){
8484                     y = vy;
8485                     moved = true;
8486                 }
8487                 return moved ? [x, y] : false;
8488             };
8489         }(),
8490
8491         // private
8492         adjustForConstraints : function(xy, parent, offsets){
8493             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8494         },
8495
8496         /**
8497          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8498          * document it aligns it to the viewport.
8499          * The position parameter is optional, and can be specified in any one of the following formats:
8500          * <ul>
8501          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8502          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8503          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8504          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8505          *   <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
8506          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8507          * </ul>
8508          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8509          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8510          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8511          * that specified in order to enforce the viewport constraints.
8512          * Following are all of the supported anchor positions:
8513     <pre>
8514     Value  Description
8515     -----  -----------------------------
8516     tl     The top left corner (default)
8517     t      The center of the top edge
8518     tr     The top right corner
8519     l      The center of the left edge
8520     c      In the center of the element
8521     r      The center of the right edge
8522     bl     The bottom left corner
8523     b      The center of the bottom edge
8524     br     The bottom right corner
8525     </pre>
8526     Example Usage:
8527     <pre><code>
8528     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8529     el.alignTo("other-el");
8530
8531     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8532     el.alignTo("other-el", "tr?");
8533
8534     // align the bottom right corner of el with the center left edge of other-el
8535     el.alignTo("other-el", "br-l?");
8536
8537     // align the center of el with the bottom left corner of other-el and
8538     // adjust the x position by -6 pixels (and the y position by 0)
8539     el.alignTo("other-el", "c-bl", [-6, 0]);
8540     </code></pre>
8541          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8542          * @param {String} position The position to align to.
8543          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8544          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8545          * @return {Roo.Element} this
8546          */
8547         alignTo : function(element, position, offsets, animate){
8548             var xy = this.getAlignToXY(element, position, offsets);
8549             this.setXY(xy, this.preanim(arguments, 3));
8550             return this;
8551         },
8552
8553         /**
8554          * Anchors an element to another element and realigns it when the window is resized.
8555          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8556          * @param {String} position The position to align to.
8557          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8558          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8559          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8560          * is a number, it is used as the buffer delay (defaults to 50ms).
8561          * @param {Function} callback The function to call after the animation finishes
8562          * @return {Roo.Element} this
8563          */
8564         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8565             var action = function(){
8566                 this.alignTo(el, alignment, offsets, animate);
8567                 Roo.callback(callback, this);
8568             };
8569             Roo.EventManager.onWindowResize(action, this);
8570             var tm = typeof monitorScroll;
8571             if(tm != 'undefined'){
8572                 Roo.EventManager.on(window, 'scroll', action, this,
8573                     {buffer: tm == 'number' ? monitorScroll : 50});
8574             }
8575             action.call(this); // align immediately
8576             return this;
8577         },
8578         /**
8579          * Clears any opacity settings from this element. Required in some cases for IE.
8580          * @return {Roo.Element} this
8581          */
8582         clearOpacity : function(){
8583             if (window.ActiveXObject) {
8584                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8585                     this.dom.style.filter = "";
8586                 }
8587             } else {
8588                 this.dom.style.opacity = "";
8589                 this.dom.style["-moz-opacity"] = "";
8590                 this.dom.style["-khtml-opacity"] = "";
8591             }
8592             return this;
8593         },
8594
8595         /**
8596          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8597          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8598          * @return {Roo.Element} this
8599          */
8600         hide : function(animate){
8601             this.setVisible(false, this.preanim(arguments, 0));
8602             return this;
8603         },
8604
8605         /**
8606         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8607         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8608          * @return {Roo.Element} this
8609          */
8610         show : function(animate){
8611             this.setVisible(true, this.preanim(arguments, 0));
8612             return this;
8613         },
8614
8615         /**
8616          * @private Test if size has a unit, otherwise appends the default
8617          */
8618         addUnits : function(size){
8619             return Roo.Element.addUnits(size, this.defaultUnit);
8620         },
8621
8622         /**
8623          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8624          * @return {Roo.Element} this
8625          */
8626         beginMeasure : function(){
8627             var el = this.dom;
8628             if(el.offsetWidth || el.offsetHeight){
8629                 return this; // offsets work already
8630             }
8631             var changed = [];
8632             var p = this.dom, b = document.body; // start with this element
8633             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8634                 var pe = Roo.get(p);
8635                 if(pe.getStyle('display') == 'none'){
8636                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8637                     p.style.visibility = "hidden";
8638                     p.style.display = "block";
8639                 }
8640                 p = p.parentNode;
8641             }
8642             this._measureChanged = changed;
8643             return this;
8644
8645         },
8646
8647         /**
8648          * Restores displays to before beginMeasure was called
8649          * @return {Roo.Element} this
8650          */
8651         endMeasure : function(){
8652             var changed = this._measureChanged;
8653             if(changed){
8654                 for(var i = 0, len = changed.length; i < len; i++) {
8655                     var r = changed[i];
8656                     r.el.style.visibility = r.visibility;
8657                     r.el.style.display = "none";
8658                 }
8659                 this._measureChanged = null;
8660             }
8661             return this;
8662         },
8663
8664         /**
8665         * Update the innerHTML of this element, optionally searching for and processing scripts
8666         * @param {String} html The new HTML
8667         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8668         * @param {Function} callback For async script loading you can be noticed when the update completes
8669         * @return {Roo.Element} this
8670          */
8671         update : function(html, loadScripts, callback){
8672             if(typeof html == "undefined"){
8673                 html = "";
8674             }
8675             if(loadScripts !== true){
8676                 this.dom.innerHTML = html;
8677                 if(typeof callback == "function"){
8678                     callback();
8679                 }
8680                 return this;
8681             }
8682             var id = Roo.id();
8683             var dom = this.dom;
8684
8685             html += '<span id="' + id + '"></span>';
8686
8687             E.onAvailable(id, function(){
8688                 var hd = document.getElementsByTagName("head")[0];
8689                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8690                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8691                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8692
8693                 var match;
8694                 while(match = re.exec(html)){
8695                     var attrs = match[1];
8696                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8697                     if(srcMatch && srcMatch[2]){
8698                        var s = document.createElement("script");
8699                        s.src = srcMatch[2];
8700                        var typeMatch = attrs.match(typeRe);
8701                        if(typeMatch && typeMatch[2]){
8702                            s.type = typeMatch[2];
8703                        }
8704                        hd.appendChild(s);
8705                     }else if(match[2] && match[2].length > 0){
8706                         if(window.execScript) {
8707                            window.execScript(match[2]);
8708                         } else {
8709                             /**
8710                              * eval:var:id
8711                              * eval:var:dom
8712                              * eval:var:html
8713                              * 
8714                              */
8715                            window.eval(match[2]);
8716                         }
8717                     }
8718                 }
8719                 var el = document.getElementById(id);
8720                 if(el){el.parentNode.removeChild(el);}
8721                 if(typeof callback == "function"){
8722                     callback();
8723                 }
8724             });
8725             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8726             return this;
8727         },
8728
8729         /**
8730          * Direct access to the UpdateManager update() method (takes the same parameters).
8731          * @param {String/Function} url The url for this request or a function to call to get the url
8732          * @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}
8733          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8734          * @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.
8735          * @return {Roo.Element} this
8736          */
8737         load : function(){
8738             var um = this.getUpdateManager();
8739             um.update.apply(um, arguments);
8740             return this;
8741         },
8742
8743         /**
8744         * Gets this element's UpdateManager
8745         * @return {Roo.UpdateManager} The UpdateManager
8746         */
8747         getUpdateManager : function(){
8748             if(!this.updateManager){
8749                 this.updateManager = new Roo.UpdateManager(this);
8750             }
8751             return this.updateManager;
8752         },
8753
8754         /**
8755          * Disables text selection for this element (normalized across browsers)
8756          * @return {Roo.Element} this
8757          */
8758         unselectable : function(){
8759             this.dom.unselectable = "on";
8760             this.swallowEvent("selectstart", true);
8761             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8762             this.addClass("x-unselectable");
8763             return this;
8764         },
8765
8766         /**
8767         * Calculates the x, y to center this element on the screen
8768         * @return {Array} The x, y values [x, y]
8769         */
8770         getCenterXY : function(){
8771             return this.getAlignToXY(document, 'c-c');
8772         },
8773
8774         /**
8775         * Centers the Element in either the viewport, or another Element.
8776         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8777         */
8778         center : function(centerIn){
8779             this.alignTo(centerIn || document, 'c-c');
8780             return this;
8781         },
8782
8783         /**
8784          * Tests various css rules/browsers to determine if this element uses a border box
8785          * @return {Boolean}
8786          */
8787         isBorderBox : function(){
8788             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8789         },
8790
8791         /**
8792          * Return a box {x, y, width, height} that can be used to set another elements
8793          * size/location to match this element.
8794          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8795          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8796          * @return {Object} box An object in the format {x, y, width, height}
8797          */
8798         getBox : function(contentBox, local){
8799             var xy;
8800             if(!local){
8801                 xy = this.getXY();
8802             }else{
8803                 var left = parseInt(this.getStyle("left"), 10) || 0;
8804                 var top = parseInt(this.getStyle("top"), 10) || 0;
8805                 xy = [left, top];
8806             }
8807             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8808             if(!contentBox){
8809                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8810             }else{
8811                 var l = this.getBorderWidth("l")+this.getPadding("l");
8812                 var r = this.getBorderWidth("r")+this.getPadding("r");
8813                 var t = this.getBorderWidth("t")+this.getPadding("t");
8814                 var b = this.getBorderWidth("b")+this.getPadding("b");
8815                 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)};
8816             }
8817             bx.right = bx.x + bx.width;
8818             bx.bottom = bx.y + bx.height;
8819             return bx;
8820         },
8821
8822         /**
8823          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8824          for more information about the sides.
8825          * @param {String} sides
8826          * @return {Number}
8827          */
8828         getFrameWidth : function(sides, onlyContentBox){
8829             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8830         },
8831
8832         /**
8833          * 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.
8834          * @param {Object} box The box to fill {x, y, width, height}
8835          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8836          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8837          * @return {Roo.Element} this
8838          */
8839         setBox : function(box, adjust, animate){
8840             var w = box.width, h = box.height;
8841             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8842                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8843                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8844             }
8845             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8846             return this;
8847         },
8848
8849         /**
8850          * Forces the browser to repaint this element
8851          * @return {Roo.Element} this
8852          */
8853          repaint : function(){
8854             var dom = this.dom;
8855             this.addClass("x-repaint");
8856             setTimeout(function(){
8857                 Roo.get(dom).removeClass("x-repaint");
8858             }, 1);
8859             return this;
8860         },
8861
8862         /**
8863          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8864          * then it returns the calculated width of the sides (see getPadding)
8865          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8866          * @return {Object/Number}
8867          */
8868         getMargins : function(side){
8869             if(!side){
8870                 return {
8871                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8872                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8873                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8874                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8875                 };
8876             }else{
8877                 return this.addStyles(side, El.margins);
8878              }
8879         },
8880
8881         // private
8882         addStyles : function(sides, styles){
8883             var val = 0, v, w;
8884             for(var i = 0, len = sides.length; i < len; i++){
8885                 v = this.getStyle(styles[sides.charAt(i)]);
8886                 if(v){
8887                      w = parseInt(v, 10);
8888                      if(w){ val += w; }
8889                 }
8890             }
8891             return val;
8892         },
8893
8894         /**
8895          * Creates a proxy element of this element
8896          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8897          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8898          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8899          * @return {Roo.Element} The new proxy element
8900          */
8901         createProxy : function(config, renderTo, matchBox){
8902             if(renderTo){
8903                 renderTo = Roo.getDom(renderTo);
8904             }else{
8905                 renderTo = document.body;
8906             }
8907             config = typeof config == "object" ?
8908                 config : {tag : "div", cls: config};
8909             var proxy = Roo.DomHelper.append(renderTo, config, true);
8910             if(matchBox){
8911                proxy.setBox(this.getBox());
8912             }
8913             return proxy;
8914         },
8915
8916         /**
8917          * Puts a mask over this element to disable user interaction. Requires core.css.
8918          * This method can only be applied to elements which accept child nodes.
8919          * @param {String} msg (optional) A message to display in the mask
8920          * @param {String} msgCls (optional) A css class to apply to the msg element
8921          * @return {Element} The mask  element
8922          */
8923         mask : function(msg, msgCls)
8924         {
8925             if(this.getStyle("position") == "static"){
8926                 this.setStyle("position", "relative");
8927             }
8928             if(!this._mask){
8929                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8930             }
8931             this.addClass("x-masked");
8932             this._mask.setDisplayed(true);
8933             
8934             // we wander
8935             var z = 0;
8936             var dom = this.dom
8937             while (dom && dom.style) {
8938                 if (!isNaN(parseInt(dom.style.zIndex))) {
8939                     z = Math.max(z, parseInt(dom.style.zIndex));
8940                 }
8941                 dom = dom.parentNode;
8942             }
8943             // if we are masking the body - then it hides everything..
8944             if (this.dom == document.body) {
8945                 z = 1000000;
8946                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8947                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8948             }
8949            
8950             if(typeof msg == 'string'){
8951                 if(!this._maskMsg){
8952                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8953                 }
8954                 var mm = this._maskMsg;
8955                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8956                 mm.dom.firstChild.innerHTML = msg;
8957                 mm.setDisplayed(true);
8958                 mm.center(this);
8959                 mm.setStyle('z-index', z + 102);
8960             }
8961             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8962                 this._mask.setHeight(this.getHeight());
8963             }
8964             this._mask.setStyle('z-index', z + 100);
8965             
8966             return this._mask;
8967         },
8968
8969         /**
8970          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8971          * it is cached for reuse.
8972          */
8973         unmask : function(removeEl){
8974             if(this._mask){
8975                 if(removeEl === true){
8976                     this._mask.remove();
8977                     delete this._mask;
8978                     if(this._maskMsg){
8979                         this._maskMsg.remove();
8980                         delete this._maskMsg;
8981                     }
8982                 }else{
8983                     this._mask.setDisplayed(false);
8984                     if(this._maskMsg){
8985                         this._maskMsg.setDisplayed(false);
8986                     }
8987                 }
8988             }
8989             this.removeClass("x-masked");
8990         },
8991
8992         /**
8993          * Returns true if this element is masked
8994          * @return {Boolean}
8995          */
8996         isMasked : function(){
8997             return this._mask && this._mask.isVisible();
8998         },
8999
9000         /**
9001          * Creates an iframe shim for this element to keep selects and other windowed objects from
9002          * showing through.
9003          * @return {Roo.Element} The new shim element
9004          */
9005         createShim : function(){
9006             var el = document.createElement('iframe');
9007             el.frameBorder = 'no';
9008             el.className = 'roo-shim';
9009             if(Roo.isIE && Roo.isSecure){
9010                 el.src = Roo.SSL_SECURE_URL;
9011             }
9012             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9013             shim.autoBoxAdjust = false;
9014             return shim;
9015         },
9016
9017         /**
9018          * Removes this element from the DOM and deletes it from the cache
9019          */
9020         remove : function(){
9021             if(this.dom.parentNode){
9022                 this.dom.parentNode.removeChild(this.dom);
9023             }
9024             delete El.cache[this.dom.id];
9025         },
9026
9027         /**
9028          * Sets up event handlers to add and remove a css class when the mouse is over this element
9029          * @param {String} className
9030          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9031          * mouseout events for children elements
9032          * @return {Roo.Element} this
9033          */
9034         addClassOnOver : function(className, preventFlicker){
9035             this.on("mouseover", function(){
9036                 Roo.fly(this, '_internal').addClass(className);
9037             }, this.dom);
9038             var removeFn = function(e){
9039                 if(preventFlicker !== true || !e.within(this, true)){
9040                     Roo.fly(this, '_internal').removeClass(className);
9041                 }
9042             };
9043             this.on("mouseout", removeFn, this.dom);
9044             return this;
9045         },
9046
9047         /**
9048          * Sets up event handlers to add and remove a css class when this element has the focus
9049          * @param {String} className
9050          * @return {Roo.Element} this
9051          */
9052         addClassOnFocus : function(className){
9053             this.on("focus", function(){
9054                 Roo.fly(this, '_internal').addClass(className);
9055             }, this.dom);
9056             this.on("blur", function(){
9057                 Roo.fly(this, '_internal').removeClass(className);
9058             }, this.dom);
9059             return this;
9060         },
9061         /**
9062          * 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)
9063          * @param {String} className
9064          * @return {Roo.Element} this
9065          */
9066         addClassOnClick : function(className){
9067             var dom = this.dom;
9068             this.on("mousedown", function(){
9069                 Roo.fly(dom, '_internal').addClass(className);
9070                 var d = Roo.get(document);
9071                 var fn = function(){
9072                     Roo.fly(dom, '_internal').removeClass(className);
9073                     d.removeListener("mouseup", fn);
9074                 };
9075                 d.on("mouseup", fn);
9076             });
9077             return this;
9078         },
9079
9080         /**
9081          * Stops the specified event from bubbling and optionally prevents the default action
9082          * @param {String} eventName
9083          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9084          * @return {Roo.Element} this
9085          */
9086         swallowEvent : function(eventName, preventDefault){
9087             var fn = function(e){
9088                 e.stopPropagation();
9089                 if(preventDefault){
9090                     e.preventDefault();
9091                 }
9092             };
9093             if(eventName instanceof Array){
9094                 for(var i = 0, len = eventName.length; i < len; i++){
9095                      this.on(eventName[i], fn);
9096                 }
9097                 return this;
9098             }
9099             this.on(eventName, fn);
9100             return this;
9101         },
9102
9103         /**
9104          * @private
9105          */
9106       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9107
9108         /**
9109          * Sizes this element to its parent element's dimensions performing
9110          * neccessary box adjustments.
9111          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9112          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9113          * @return {Roo.Element} this
9114          */
9115         fitToParent : function(monitorResize, targetParent) {
9116           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9117           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9118           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9119             return;
9120           }
9121           var p = Roo.get(targetParent || this.dom.parentNode);
9122           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9123           if (monitorResize === true) {
9124             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9125             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9126           }
9127           return this;
9128         },
9129
9130         /**
9131          * Gets the next sibling, skipping text nodes
9132          * @return {HTMLElement} The next sibling or null
9133          */
9134         getNextSibling : function(){
9135             var n = this.dom.nextSibling;
9136             while(n && n.nodeType != 1){
9137                 n = n.nextSibling;
9138             }
9139             return n;
9140         },
9141
9142         /**
9143          * Gets the previous sibling, skipping text nodes
9144          * @return {HTMLElement} The previous sibling or null
9145          */
9146         getPrevSibling : function(){
9147             var n = this.dom.previousSibling;
9148             while(n && n.nodeType != 1){
9149                 n = n.previousSibling;
9150             }
9151             return n;
9152         },
9153
9154
9155         /**
9156          * Appends the passed element(s) to this element
9157          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9158          * @return {Roo.Element} this
9159          */
9160         appendChild: function(el){
9161             el = Roo.get(el);
9162             el.appendTo(this);
9163             return this;
9164         },
9165
9166         /**
9167          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9168          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9169          * automatically generated with the specified attributes.
9170          * @param {HTMLElement} insertBefore (optional) a child element of this element
9171          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9172          * @return {Roo.Element} The new child element
9173          */
9174         createChild: function(config, insertBefore, returnDom){
9175             config = config || {tag:'div'};
9176             if(insertBefore){
9177                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9178             }
9179             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9180         },
9181
9182         /**
9183          * Appends this element to the passed element
9184          * @param {String/HTMLElement/Element} el The new parent element
9185          * @return {Roo.Element} this
9186          */
9187         appendTo: function(el){
9188             el = Roo.getDom(el);
9189             el.appendChild(this.dom);
9190             return this;
9191         },
9192
9193         /**
9194          * Inserts this element before the passed element in the DOM
9195          * @param {String/HTMLElement/Element} el The element to insert before
9196          * @return {Roo.Element} this
9197          */
9198         insertBefore: function(el){
9199             el = Roo.getDom(el);
9200             el.parentNode.insertBefore(this.dom, el);
9201             return this;
9202         },
9203
9204         /**
9205          * Inserts this element after the passed element in the DOM
9206          * @param {String/HTMLElement/Element} el The element to insert after
9207          * @return {Roo.Element} this
9208          */
9209         insertAfter: function(el){
9210             el = Roo.getDom(el);
9211             el.parentNode.insertBefore(this.dom, el.nextSibling);
9212             return this;
9213         },
9214
9215         /**
9216          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9217          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9218          * @return {Roo.Element} The new child
9219          */
9220         insertFirst: function(el, returnDom){
9221             el = el || {};
9222             if(typeof el == 'object' && !el.nodeType){ // dh config
9223                 return this.createChild(el, this.dom.firstChild, returnDom);
9224             }else{
9225                 el = Roo.getDom(el);
9226                 this.dom.insertBefore(el, this.dom.firstChild);
9227                 return !returnDom ? Roo.get(el) : el;
9228             }
9229         },
9230
9231         /**
9232          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9233          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9234          * @param {String} where (optional) 'before' or 'after' defaults to before
9235          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9236          * @return {Roo.Element} the inserted Element
9237          */
9238         insertSibling: function(el, where, returnDom){
9239             where = where ? where.toLowerCase() : 'before';
9240             el = el || {};
9241             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9242
9243             if(typeof el == 'object' && !el.nodeType){ // dh config
9244                 if(where == 'after' && !this.dom.nextSibling){
9245                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9246                 }else{
9247                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9248                 }
9249
9250             }else{
9251                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9252                             where == 'before' ? this.dom : this.dom.nextSibling);
9253                 if(!returnDom){
9254                     rt = Roo.get(rt);
9255                 }
9256             }
9257             return rt;
9258         },
9259
9260         /**
9261          * Creates and wraps this element with another element
9262          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9263          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9264          * @return {HTMLElement/Element} The newly created wrapper element
9265          */
9266         wrap: function(config, returnDom){
9267             if(!config){
9268                 config = {tag: "div"};
9269             }
9270             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9271             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9272             return newEl;
9273         },
9274
9275         /**
9276          * Replaces the passed element with this element
9277          * @param {String/HTMLElement/Element} el The element to replace
9278          * @return {Roo.Element} this
9279          */
9280         replace: function(el){
9281             el = Roo.get(el);
9282             this.insertBefore(el);
9283             el.remove();
9284             return this;
9285         },
9286
9287         /**
9288          * Inserts an html fragment into this element
9289          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9290          * @param {String} html The HTML fragment
9291          * @param {Boolean} returnEl True to return an Roo.Element
9292          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9293          */
9294         insertHtml : function(where, html, returnEl){
9295             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9296             return returnEl ? Roo.get(el) : el;
9297         },
9298
9299         /**
9300          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9301          * @param {Object} o The object with the attributes
9302          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9303          * @return {Roo.Element} this
9304          */
9305         set : function(o, useSet){
9306             var el = this.dom;
9307             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9308             for(var attr in o){
9309                 if(attr == "style" || typeof o[attr] == "function") continue;
9310                 if(attr=="cls"){
9311                     el.className = o["cls"];
9312                 }else{
9313                     if(useSet) el.setAttribute(attr, o[attr]);
9314                     else el[attr] = o[attr];
9315                 }
9316             }
9317             if(o.style){
9318                 Roo.DomHelper.applyStyles(el, o.style);
9319             }
9320             return this;
9321         },
9322
9323         /**
9324          * Convenience method for constructing a KeyMap
9325          * @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:
9326          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9327          * @param {Function} fn The function to call
9328          * @param {Object} scope (optional) The scope of the function
9329          * @return {Roo.KeyMap} The KeyMap created
9330          */
9331         addKeyListener : function(key, fn, scope){
9332             var config;
9333             if(typeof key != "object" || key instanceof Array){
9334                 config = {
9335                     key: key,
9336                     fn: fn,
9337                     scope: scope
9338                 };
9339             }else{
9340                 config = {
9341                     key : key.key,
9342                     shift : key.shift,
9343                     ctrl : key.ctrl,
9344                     alt : key.alt,
9345                     fn: fn,
9346                     scope: scope
9347                 };
9348             }
9349             return new Roo.KeyMap(this, config);
9350         },
9351
9352         /**
9353          * Creates a KeyMap for this element
9354          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9355          * @return {Roo.KeyMap} The KeyMap created
9356          */
9357         addKeyMap : function(config){
9358             return new Roo.KeyMap(this, config);
9359         },
9360
9361         /**
9362          * Returns true if this element is scrollable.
9363          * @return {Boolean}
9364          */
9365          isScrollable : function(){
9366             var dom = this.dom;
9367             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9368         },
9369
9370         /**
9371          * 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().
9372          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9373          * @param {Number} value The new scroll value
9374          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9375          * @return {Element} this
9376          */
9377
9378         scrollTo : function(side, value, animate){
9379             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9380             if(!animate || !A){
9381                 this.dom[prop] = value;
9382             }else{
9383                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9384                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9385             }
9386             return this;
9387         },
9388
9389         /**
9390          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9391          * within this element's scrollable range.
9392          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9393          * @param {Number} distance How far to scroll the element in pixels
9394          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9395          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9396          * was scrolled as far as it could go.
9397          */
9398          scroll : function(direction, distance, animate){
9399              if(!this.isScrollable()){
9400                  return;
9401              }
9402              var el = this.dom;
9403              var l = el.scrollLeft, t = el.scrollTop;
9404              var w = el.scrollWidth, h = el.scrollHeight;
9405              var cw = el.clientWidth, ch = el.clientHeight;
9406              direction = direction.toLowerCase();
9407              var scrolled = false;
9408              var a = this.preanim(arguments, 2);
9409              switch(direction){
9410                  case "l":
9411                  case "left":
9412                      if(w - l > cw){
9413                          var v = Math.min(l + distance, w-cw);
9414                          this.scrollTo("left", v, a);
9415                          scrolled = true;
9416                      }
9417                      break;
9418                 case "r":
9419                 case "right":
9420                      if(l > 0){
9421                          var v = Math.max(l - distance, 0);
9422                          this.scrollTo("left", v, a);
9423                          scrolled = true;
9424                      }
9425                      break;
9426                 case "t":
9427                 case "top":
9428                 case "up":
9429                      if(t > 0){
9430                          var v = Math.max(t - distance, 0);
9431                          this.scrollTo("top", v, a);
9432                          scrolled = true;
9433                      }
9434                      break;
9435                 case "b":
9436                 case "bottom":
9437                 case "down":
9438                      if(h - t > ch){
9439                          var v = Math.min(t + distance, h-ch);
9440                          this.scrollTo("top", v, a);
9441                          scrolled = true;
9442                      }
9443                      break;
9444              }
9445              return scrolled;
9446         },
9447
9448         /**
9449          * Translates the passed page coordinates into left/top css values for this element
9450          * @param {Number/Array} x The page x or an array containing [x, y]
9451          * @param {Number} y The page y
9452          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9453          */
9454         translatePoints : function(x, y){
9455             if(typeof x == 'object' || x instanceof Array){
9456                 y = x[1]; x = x[0];
9457             }
9458             var p = this.getStyle('position');
9459             var o = this.getXY();
9460
9461             var l = parseInt(this.getStyle('left'), 10);
9462             var t = parseInt(this.getStyle('top'), 10);
9463
9464             if(isNaN(l)){
9465                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9466             }
9467             if(isNaN(t)){
9468                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9469             }
9470
9471             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9472         },
9473
9474         /**
9475          * Returns the current scroll position of the element.
9476          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9477          */
9478         getScroll : function(){
9479             var d = this.dom, doc = document;
9480             if(d == doc || d == doc.body){
9481                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9482                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9483                 return {left: l, top: t};
9484             }else{
9485                 return {left: d.scrollLeft, top: d.scrollTop};
9486             }
9487         },
9488
9489         /**
9490          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9491          * are convert to standard 6 digit hex color.
9492          * @param {String} attr The css attribute
9493          * @param {String} defaultValue The default value to use when a valid color isn't found
9494          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9495          * YUI color anims.
9496          */
9497         getColor : function(attr, defaultValue, prefix){
9498             var v = this.getStyle(attr);
9499             if(!v || v == "transparent" || v == "inherit") {
9500                 return defaultValue;
9501             }
9502             var color = typeof prefix == "undefined" ? "#" : prefix;
9503             if(v.substr(0, 4) == "rgb("){
9504                 var rvs = v.slice(4, v.length -1).split(",");
9505                 for(var i = 0; i < 3; i++){
9506                     var h = parseInt(rvs[i]).toString(16);
9507                     if(h < 16){
9508                         h = "0" + h;
9509                     }
9510                     color += h;
9511                 }
9512             } else {
9513                 if(v.substr(0, 1) == "#"){
9514                     if(v.length == 4) {
9515                         for(var i = 1; i < 4; i++){
9516                             var c = v.charAt(i);
9517                             color +=  c + c;
9518                         }
9519                     }else if(v.length == 7){
9520                         color += v.substr(1);
9521                     }
9522                 }
9523             }
9524             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9525         },
9526
9527         /**
9528          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9529          * gradient background, rounded corners and a 4-way shadow.
9530          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9531          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9532          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9533          * @return {Roo.Element} this
9534          */
9535         boxWrap : function(cls){
9536             cls = cls || 'x-box';
9537             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9538             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9539             return el;
9540         },
9541
9542         /**
9543          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9544          * @param {String} namespace The namespace in which to look for the attribute
9545          * @param {String} name The attribute name
9546          * @return {String} The attribute value
9547          */
9548         getAttributeNS : Roo.isIE ? function(ns, name){
9549             var d = this.dom;
9550             var type = typeof d[ns+":"+name];
9551             if(type != 'undefined' && type != 'unknown'){
9552                 return d[ns+":"+name];
9553             }
9554             return d[name];
9555         } : function(ns, name){
9556             var d = this.dom;
9557             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9558         },
9559         
9560         
9561         /**
9562          * Sets or Returns the value the dom attribute value
9563          * @param {String} name The attribute name
9564          * @param {String} name (optional) The attribute name
9565          * @return {String} The attribute value
9566          */
9567         attr : function(name){
9568             if (arguments.length > 1) {
9569                 this.dom.setAttribute(name, arguments[1]);
9570                 return arguments[1];
9571             }
9572             if (!this.dom.hasAttribute(name)) {
9573                 return undefined;
9574             }
9575             return this.dom.getAttribute(name);
9576         }
9577         
9578         
9579         
9580     };
9581
9582     var ep = El.prototype;
9583
9584     /**
9585      * Appends an event handler (Shorthand for addListener)
9586      * @param {String}   eventName     The type of event to append
9587      * @param {Function} fn        The method the event invokes
9588      * @param {Object} scope       (optional) The scope (this object) of the fn
9589      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9590      * @method
9591      */
9592     ep.on = ep.addListener;
9593         // backwards compat
9594     ep.mon = ep.addListener;
9595
9596     /**
9597      * Removes an event handler from this element (shorthand for removeListener)
9598      * @param {String} eventName the type of event to remove
9599      * @param {Function} fn the method the event invokes
9600      * @return {Roo.Element} this
9601      * @method
9602      */
9603     ep.un = ep.removeListener;
9604
9605     /**
9606      * true to automatically adjust width and height settings for box-model issues (default to true)
9607      */
9608     ep.autoBoxAdjust = true;
9609
9610     // private
9611     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9612
9613     // private
9614     El.addUnits = function(v, defaultUnit){
9615         if(v === "" || v == "auto"){
9616             return v;
9617         }
9618         if(v === undefined){
9619             return '';
9620         }
9621         if(typeof v == "number" || !El.unitPattern.test(v)){
9622             return v + (defaultUnit || 'px');
9623         }
9624         return v;
9625     };
9626
9627     // special markup used throughout Roo when box wrapping elements
9628     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>';
9629     /**
9630      * Visibility mode constant - Use visibility to hide element
9631      * @static
9632      * @type Number
9633      */
9634     El.VISIBILITY = 1;
9635     /**
9636      * Visibility mode constant - Use display to hide element
9637      * @static
9638      * @type Number
9639      */
9640     El.DISPLAY = 2;
9641
9642     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9643     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9644     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9645
9646
9647
9648     /**
9649      * @private
9650      */
9651     El.cache = {};
9652
9653     var docEl;
9654
9655     /**
9656      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9657      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9658      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9659      * @return {Element} The Element object
9660      * @static
9661      */
9662     El.get = function(el){
9663         var ex, elm, id;
9664         if(!el){ return null; }
9665         if(typeof el == "string"){ // element id
9666             if(!(elm = document.getElementById(el))){
9667                 return null;
9668             }
9669             if(ex = El.cache[el]){
9670                 ex.dom = elm;
9671             }else{
9672                 ex = El.cache[el] = new El(elm);
9673             }
9674             return ex;
9675         }else if(el.tagName){ // dom element
9676             if(!(id = el.id)){
9677                 id = Roo.id(el);
9678             }
9679             if(ex = El.cache[id]){
9680                 ex.dom = el;
9681             }else{
9682                 ex = El.cache[id] = new El(el);
9683             }
9684             return ex;
9685         }else if(el instanceof El){
9686             if(el != docEl){
9687                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9688                                                               // catch case where it hasn't been appended
9689                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9690             }
9691             return el;
9692         }else if(el.isComposite){
9693             return el;
9694         }else if(el instanceof Array){
9695             return El.select(el);
9696         }else if(el == document){
9697             // create a bogus element object representing the document object
9698             if(!docEl){
9699                 var f = function(){};
9700                 f.prototype = El.prototype;
9701                 docEl = new f();
9702                 docEl.dom = document;
9703             }
9704             return docEl;
9705         }
9706         return null;
9707     };
9708
9709     // private
9710     El.uncache = function(el){
9711         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9712             if(a[i]){
9713                 delete El.cache[a[i].id || a[i]];
9714             }
9715         }
9716     };
9717
9718     // private
9719     // Garbage collection - uncache elements/purge listeners on orphaned elements
9720     // so we don't hold a reference and cause the browser to retain them
9721     El.garbageCollect = function(){
9722         if(!Roo.enableGarbageCollector){
9723             clearInterval(El.collectorThread);
9724             return;
9725         }
9726         for(var eid in El.cache){
9727             var el = El.cache[eid], d = el.dom;
9728             // -------------------------------------------------------
9729             // Determining what is garbage:
9730             // -------------------------------------------------------
9731             // !d
9732             // dom node is null, definitely garbage
9733             // -------------------------------------------------------
9734             // !d.parentNode
9735             // no parentNode == direct orphan, definitely garbage
9736             // -------------------------------------------------------
9737             // !d.offsetParent && !document.getElementById(eid)
9738             // display none elements have no offsetParent so we will
9739             // also try to look it up by it's id. However, check
9740             // offsetParent first so we don't do unneeded lookups.
9741             // This enables collection of elements that are not orphans
9742             // directly, but somewhere up the line they have an orphan
9743             // parent.
9744             // -------------------------------------------------------
9745             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9746                 delete El.cache[eid];
9747                 if(d && Roo.enableListenerCollection){
9748                     E.purgeElement(d);
9749                 }
9750             }
9751         }
9752     }
9753     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9754
9755
9756     // dom is optional
9757     El.Flyweight = function(dom){
9758         this.dom = dom;
9759     };
9760     El.Flyweight.prototype = El.prototype;
9761
9762     El._flyweights = {};
9763     /**
9764      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9765      * the dom node can be overwritten by other code.
9766      * @param {String/HTMLElement} el The dom node or id
9767      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9768      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9769      * @static
9770      * @return {Element} The shared Element object
9771      */
9772     El.fly = function(el, named){
9773         named = named || '_global';
9774         el = Roo.getDom(el);
9775         if(!el){
9776             return null;
9777         }
9778         if(!El._flyweights[named]){
9779             El._flyweights[named] = new El.Flyweight();
9780         }
9781         El._flyweights[named].dom = el;
9782         return El._flyweights[named];
9783     };
9784
9785     /**
9786      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9787      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9788      * Shorthand of {@link Roo.Element#get}
9789      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9790      * @return {Element} The Element object
9791      * @member Roo
9792      * @method get
9793      */
9794     Roo.get = El.get;
9795     /**
9796      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9797      * the dom node can be overwritten by other code.
9798      * Shorthand of {@link Roo.Element#fly}
9799      * @param {String/HTMLElement} el The dom node or id
9800      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9801      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9802      * @static
9803      * @return {Element} The shared Element object
9804      * @member Roo
9805      * @method fly
9806      */
9807     Roo.fly = El.fly;
9808
9809     // speedy lookup for elements never to box adjust
9810     var noBoxAdjust = Roo.isStrict ? {
9811         select:1
9812     } : {
9813         input:1, select:1, textarea:1
9814     };
9815     if(Roo.isIE || Roo.isGecko){
9816         noBoxAdjust['button'] = 1;
9817     }
9818
9819
9820     Roo.EventManager.on(window, 'unload', function(){
9821         delete El.cache;
9822         delete El._flyweights;
9823     });
9824 })();
9825
9826
9827
9828
9829 if(Roo.DomQuery){
9830     Roo.Element.selectorFunction = Roo.DomQuery.select;
9831 }
9832
9833 Roo.Element.select = function(selector, unique, root){
9834     var els;
9835     if(typeof selector == "string"){
9836         els = Roo.Element.selectorFunction(selector, root);
9837     }else if(selector.length !== undefined){
9838         els = selector;
9839     }else{
9840         throw "Invalid selector";
9841     }
9842     if(unique === true){
9843         return new Roo.CompositeElement(els);
9844     }else{
9845         return new Roo.CompositeElementLite(els);
9846     }
9847 };
9848 /**
9849  * Selects elements based on the passed CSS selector to enable working on them as 1.
9850  * @param {String/Array} selector The CSS selector or an array of elements
9851  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9852  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9853  * @return {CompositeElementLite/CompositeElement}
9854  * @member Roo
9855  * @method select
9856  */
9857 Roo.select = Roo.Element.select;
9858
9859
9860
9861
9862
9863
9864
9865
9866
9867
9868
9869
9870
9871
9872 /*
9873  * Based on:
9874  * Ext JS Library 1.1.1
9875  * Copyright(c) 2006-2007, Ext JS, LLC.
9876  *
9877  * Originally Released Under LGPL - original licence link has changed is not relivant.
9878  *
9879  * Fork - LGPL
9880  * <script type="text/javascript">
9881  */
9882
9883
9884
9885 //Notifies Element that fx methods are available
9886 Roo.enableFx = true;
9887
9888 /**
9889  * @class Roo.Fx
9890  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9891  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9892  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9893  * Element effects to work.</p><br/>
9894  *
9895  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9896  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9897  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9898  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9899  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9900  * expected results and should be done with care.</p><br/>
9901  *
9902  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9903  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9904 <pre>
9905 Value  Description
9906 -----  -----------------------------
9907 tl     The top left corner
9908 t      The center of the top edge
9909 tr     The top right corner
9910 l      The center of the left edge
9911 r      The center of the right edge
9912 bl     The bottom left corner
9913 b      The center of the bottom edge
9914 br     The bottom right corner
9915 </pre>
9916  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9917  * below are common options that can be passed to any Fx method.</b>
9918  * @cfg {Function} callback A function called when the effect is finished
9919  * @cfg {Object} scope The scope of the effect function
9920  * @cfg {String} easing A valid Easing value for the effect
9921  * @cfg {String} afterCls A css class to apply after the effect
9922  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9923  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9924  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9925  * effects that end with the element being visually hidden, ignored otherwise)
9926  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9927  * a function which returns such a specification that will be applied to the Element after the effect finishes
9928  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9929  * @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
9930  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9931  */
9932 Roo.Fx = {
9933         /**
9934          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9935          * origin for the slide effect.  This function automatically handles wrapping the element with
9936          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9937          * Usage:
9938          *<pre><code>
9939 // default: slide the element in from the top
9940 el.slideIn();
9941
9942 // custom: slide the element in from the right with a 2-second duration
9943 el.slideIn('r', { duration: 2 });
9944
9945 // common config options shown with default values
9946 el.slideIn('t', {
9947     easing: 'easeOut',
9948     duration: .5
9949 });
9950 </code></pre>
9951          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9952          * @param {Object} options (optional) Object literal with any of the Fx config options
9953          * @return {Roo.Element} The Element
9954          */
9955     slideIn : function(anchor, o){
9956         var el = this.getFxEl();
9957         o = o || {};
9958
9959         el.queueFx(o, function(){
9960
9961             anchor = anchor || "t";
9962
9963             // fix display to visibility
9964             this.fixDisplay();
9965
9966             // restore values after effect
9967             var r = this.getFxRestore();
9968             var b = this.getBox();
9969             // fixed size for slide
9970             this.setSize(b);
9971
9972             // wrap if needed
9973             var wrap = this.fxWrap(r.pos, o, "hidden");
9974
9975             var st = this.dom.style;
9976             st.visibility = "visible";
9977             st.position = "absolute";
9978
9979             // clear out temp styles after slide and unwrap
9980             var after = function(){
9981                 el.fxUnwrap(wrap, r.pos, o);
9982                 st.width = r.width;
9983                 st.height = r.height;
9984                 el.afterFx(o);
9985             };
9986             // time to calc the positions
9987             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9988
9989             switch(anchor.toLowerCase()){
9990                 case "t":
9991                     wrap.setSize(b.width, 0);
9992                     st.left = st.bottom = "0";
9993                     a = {height: bh};
9994                 break;
9995                 case "l":
9996                     wrap.setSize(0, b.height);
9997                     st.right = st.top = "0";
9998                     a = {width: bw};
9999                 break;
10000                 case "r":
10001                     wrap.setSize(0, b.height);
10002                     wrap.setX(b.right);
10003                     st.left = st.top = "0";
10004                     a = {width: bw, points: pt};
10005                 break;
10006                 case "b":
10007                     wrap.setSize(b.width, 0);
10008                     wrap.setY(b.bottom);
10009                     st.left = st.top = "0";
10010                     a = {height: bh, points: pt};
10011                 break;
10012                 case "tl":
10013                     wrap.setSize(0, 0);
10014                     st.right = st.bottom = "0";
10015                     a = {width: bw, height: bh};
10016                 break;
10017                 case "bl":
10018                     wrap.setSize(0, 0);
10019                     wrap.setY(b.y+b.height);
10020                     st.right = st.top = "0";
10021                     a = {width: bw, height: bh, points: pt};
10022                 break;
10023                 case "br":
10024                     wrap.setSize(0, 0);
10025                     wrap.setXY([b.right, b.bottom]);
10026                     st.left = st.top = "0";
10027                     a = {width: bw, height: bh, points: pt};
10028                 break;
10029                 case "tr":
10030                     wrap.setSize(0, 0);
10031                     wrap.setX(b.x+b.width);
10032                     st.left = st.bottom = "0";
10033                     a = {width: bw, height: bh, points: pt};
10034                 break;
10035             }
10036             this.dom.style.visibility = "visible";
10037             wrap.show();
10038
10039             arguments.callee.anim = wrap.fxanim(a,
10040                 o,
10041                 'motion',
10042                 .5,
10043                 'easeOut', after);
10044         });
10045         return this;
10046     },
10047     
10048         /**
10049          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10050          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10051          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10052          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10053          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10054          * Usage:
10055          *<pre><code>
10056 // default: slide the element out to the top
10057 el.slideOut();
10058
10059 // custom: slide the element out to the right with a 2-second duration
10060 el.slideOut('r', { duration: 2 });
10061
10062 // common config options shown with default values
10063 el.slideOut('t', {
10064     easing: 'easeOut',
10065     duration: .5,
10066     remove: false,
10067     useDisplay: false
10068 });
10069 </code></pre>
10070          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10071          * @param {Object} options (optional) Object literal with any of the Fx config options
10072          * @return {Roo.Element} The Element
10073          */
10074     slideOut : function(anchor, o){
10075         var el = this.getFxEl();
10076         o = o || {};
10077
10078         el.queueFx(o, function(){
10079
10080             anchor = anchor || "t";
10081
10082             // restore values after effect
10083             var r = this.getFxRestore();
10084             
10085             var b = this.getBox();
10086             // fixed size for slide
10087             this.setSize(b);
10088
10089             // wrap if needed
10090             var wrap = this.fxWrap(r.pos, o, "visible");
10091
10092             var st = this.dom.style;
10093             st.visibility = "visible";
10094             st.position = "absolute";
10095
10096             wrap.setSize(b);
10097
10098             var after = function(){
10099                 if(o.useDisplay){
10100                     el.setDisplayed(false);
10101                 }else{
10102                     el.hide();
10103                 }
10104
10105                 el.fxUnwrap(wrap, r.pos, o);
10106
10107                 st.width = r.width;
10108                 st.height = r.height;
10109
10110                 el.afterFx(o);
10111             };
10112
10113             var a, zero = {to: 0};
10114             switch(anchor.toLowerCase()){
10115                 case "t":
10116                     st.left = st.bottom = "0";
10117                     a = {height: zero};
10118                 break;
10119                 case "l":
10120                     st.right = st.top = "0";
10121                     a = {width: zero};
10122                 break;
10123                 case "r":
10124                     st.left = st.top = "0";
10125                     a = {width: zero, points: {to:[b.right, b.y]}};
10126                 break;
10127                 case "b":
10128                     st.left = st.top = "0";
10129                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10130                 break;
10131                 case "tl":
10132                     st.right = st.bottom = "0";
10133                     a = {width: zero, height: zero};
10134                 break;
10135                 case "bl":
10136                     st.right = st.top = "0";
10137                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10138                 break;
10139                 case "br":
10140                     st.left = st.top = "0";
10141                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10142                 break;
10143                 case "tr":
10144                     st.left = st.bottom = "0";
10145                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10146                 break;
10147             }
10148
10149             arguments.callee.anim = wrap.fxanim(a,
10150                 o,
10151                 'motion',
10152                 .5,
10153                 "easeOut", after);
10154         });
10155         return this;
10156     },
10157
10158         /**
10159          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10160          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10161          * The element must be removed from the DOM using the 'remove' config option if desired.
10162          * Usage:
10163          *<pre><code>
10164 // default
10165 el.puff();
10166
10167 // common config options shown with default values
10168 el.puff({
10169     easing: 'easeOut',
10170     duration: .5,
10171     remove: false,
10172     useDisplay: false
10173 });
10174 </code></pre>
10175          * @param {Object} options (optional) Object literal with any of the Fx config options
10176          * @return {Roo.Element} The Element
10177          */
10178     puff : function(o){
10179         var el = this.getFxEl();
10180         o = o || {};
10181
10182         el.queueFx(o, function(){
10183             this.clearOpacity();
10184             this.show();
10185
10186             // restore values after effect
10187             var r = this.getFxRestore();
10188             var st = this.dom.style;
10189
10190             var after = function(){
10191                 if(o.useDisplay){
10192                     el.setDisplayed(false);
10193                 }else{
10194                     el.hide();
10195                 }
10196
10197                 el.clearOpacity();
10198
10199                 el.setPositioning(r.pos);
10200                 st.width = r.width;
10201                 st.height = r.height;
10202                 st.fontSize = '';
10203                 el.afterFx(o);
10204             };
10205
10206             var width = this.getWidth();
10207             var height = this.getHeight();
10208
10209             arguments.callee.anim = this.fxanim({
10210                     width : {to: this.adjustWidth(width * 2)},
10211                     height : {to: this.adjustHeight(height * 2)},
10212                     points : {by: [-(width * .5), -(height * .5)]},
10213                     opacity : {to: 0},
10214                     fontSize: {to:200, unit: "%"}
10215                 },
10216                 o,
10217                 'motion',
10218                 .5,
10219                 "easeOut", after);
10220         });
10221         return this;
10222     },
10223
10224         /**
10225          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10226          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10227          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10228          * Usage:
10229          *<pre><code>
10230 // default
10231 el.switchOff();
10232
10233 // all config options shown with default values
10234 el.switchOff({
10235     easing: 'easeIn',
10236     duration: .3,
10237     remove: false,
10238     useDisplay: false
10239 });
10240 </code></pre>
10241          * @param {Object} options (optional) Object literal with any of the Fx config options
10242          * @return {Roo.Element} The Element
10243          */
10244     switchOff : function(o){
10245         var el = this.getFxEl();
10246         o = o || {};
10247
10248         el.queueFx(o, function(){
10249             this.clearOpacity();
10250             this.clip();
10251
10252             // restore values after effect
10253             var r = this.getFxRestore();
10254             var st = this.dom.style;
10255
10256             var after = function(){
10257                 if(o.useDisplay){
10258                     el.setDisplayed(false);
10259                 }else{
10260                     el.hide();
10261                 }
10262
10263                 el.clearOpacity();
10264                 el.setPositioning(r.pos);
10265                 st.width = r.width;
10266                 st.height = r.height;
10267
10268                 el.afterFx(o);
10269             };
10270
10271             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10272                 this.clearOpacity();
10273                 (function(){
10274                     this.fxanim({
10275                         height:{to:1},
10276                         points:{by:[0, this.getHeight() * .5]}
10277                     }, o, 'motion', 0.3, 'easeIn', after);
10278                 }).defer(100, this);
10279             });
10280         });
10281         return this;
10282     },
10283
10284     /**
10285      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10286      * changed using the "attr" config option) and then fading back to the original color. If no original
10287      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10288      * Usage:
10289 <pre><code>
10290 // default: highlight background to yellow
10291 el.highlight();
10292
10293 // custom: highlight foreground text to blue for 2 seconds
10294 el.highlight("0000ff", { attr: 'color', duration: 2 });
10295
10296 // common config options shown with default values
10297 el.highlight("ffff9c", {
10298     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10299     endColor: (current color) or "ffffff",
10300     easing: 'easeIn',
10301     duration: 1
10302 });
10303 </code></pre>
10304      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10305      * @param {Object} options (optional) Object literal with any of the Fx config options
10306      * @return {Roo.Element} The Element
10307      */ 
10308     highlight : function(color, o){
10309         var el = this.getFxEl();
10310         o = o || {};
10311
10312         el.queueFx(o, function(){
10313             color = color || "ffff9c";
10314             attr = o.attr || "backgroundColor";
10315
10316             this.clearOpacity();
10317             this.show();
10318
10319             var origColor = this.getColor(attr);
10320             var restoreColor = this.dom.style[attr];
10321             endColor = (o.endColor || origColor) || "ffffff";
10322
10323             var after = function(){
10324                 el.dom.style[attr] = restoreColor;
10325                 el.afterFx(o);
10326             };
10327
10328             var a = {};
10329             a[attr] = {from: color, to: endColor};
10330             arguments.callee.anim = this.fxanim(a,
10331                 o,
10332                 'color',
10333                 1,
10334                 'easeIn', after);
10335         });
10336         return this;
10337     },
10338
10339    /**
10340     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10341     * Usage:
10342 <pre><code>
10343 // default: a single light blue ripple
10344 el.frame();
10345
10346 // custom: 3 red ripples lasting 3 seconds total
10347 el.frame("ff0000", 3, { duration: 3 });
10348
10349 // common config options shown with default values
10350 el.frame("C3DAF9", 1, {
10351     duration: 1 //duration of entire animation (not each individual ripple)
10352     // Note: Easing is not configurable and will be ignored if included
10353 });
10354 </code></pre>
10355     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10356     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10357     * @param {Object} options (optional) Object literal with any of the Fx config options
10358     * @return {Roo.Element} The Element
10359     */
10360     frame : function(color, count, o){
10361         var el = this.getFxEl();
10362         o = o || {};
10363
10364         el.queueFx(o, function(){
10365             color = color || "#C3DAF9";
10366             if(color.length == 6){
10367                 color = "#" + color;
10368             }
10369             count = count || 1;
10370             duration = o.duration || 1;
10371             this.show();
10372
10373             var b = this.getBox();
10374             var animFn = function(){
10375                 var proxy = this.createProxy({
10376
10377                      style:{
10378                         visbility:"hidden",
10379                         position:"absolute",
10380                         "z-index":"35000", // yee haw
10381                         border:"0px solid " + color
10382                      }
10383                   });
10384                 var scale = Roo.isBorderBox ? 2 : 1;
10385                 proxy.animate({
10386                     top:{from:b.y, to:b.y - 20},
10387                     left:{from:b.x, to:b.x - 20},
10388                     borderWidth:{from:0, to:10},
10389                     opacity:{from:1, to:0},
10390                     height:{from:b.height, to:(b.height + (20*scale))},
10391                     width:{from:b.width, to:(b.width + (20*scale))}
10392                 }, duration, function(){
10393                     proxy.remove();
10394                 });
10395                 if(--count > 0){
10396                      animFn.defer((duration/2)*1000, this);
10397                 }else{
10398                     el.afterFx(o);
10399                 }
10400             };
10401             animFn.call(this);
10402         });
10403         return this;
10404     },
10405
10406    /**
10407     * Creates a pause before any subsequent queued effects begin.  If there are
10408     * no effects queued after the pause it will have no effect.
10409     * Usage:
10410 <pre><code>
10411 el.pause(1);
10412 </code></pre>
10413     * @param {Number} seconds The length of time to pause (in seconds)
10414     * @return {Roo.Element} The Element
10415     */
10416     pause : function(seconds){
10417         var el = this.getFxEl();
10418         var o = {};
10419
10420         el.queueFx(o, function(){
10421             setTimeout(function(){
10422                 el.afterFx(o);
10423             }, seconds * 1000);
10424         });
10425         return this;
10426     },
10427
10428    /**
10429     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10430     * using the "endOpacity" config option.
10431     * Usage:
10432 <pre><code>
10433 // default: fade in from opacity 0 to 100%
10434 el.fadeIn();
10435
10436 // custom: fade in from opacity 0 to 75% over 2 seconds
10437 el.fadeIn({ endOpacity: .75, duration: 2});
10438
10439 // common config options shown with default values
10440 el.fadeIn({
10441     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10442     easing: 'easeOut',
10443     duration: .5
10444 });
10445 </code></pre>
10446     * @param {Object} options (optional) Object literal with any of the Fx config options
10447     * @return {Roo.Element} The Element
10448     */
10449     fadeIn : function(o){
10450         var el = this.getFxEl();
10451         o = o || {};
10452         el.queueFx(o, function(){
10453             this.setOpacity(0);
10454             this.fixDisplay();
10455             this.dom.style.visibility = 'visible';
10456             var to = o.endOpacity || 1;
10457             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10458                 o, null, .5, "easeOut", function(){
10459                 if(to == 1){
10460                     this.clearOpacity();
10461                 }
10462                 el.afterFx(o);
10463             });
10464         });
10465         return this;
10466     },
10467
10468    /**
10469     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10470     * using the "endOpacity" config option.
10471     * Usage:
10472 <pre><code>
10473 // default: fade out from the element's current opacity to 0
10474 el.fadeOut();
10475
10476 // custom: fade out from the element's current opacity to 25% over 2 seconds
10477 el.fadeOut({ endOpacity: .25, duration: 2});
10478
10479 // common config options shown with default values
10480 el.fadeOut({
10481     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10482     easing: 'easeOut',
10483     duration: .5
10484     remove: false,
10485     useDisplay: false
10486 });
10487 </code></pre>
10488     * @param {Object} options (optional) Object literal with any of the Fx config options
10489     * @return {Roo.Element} The Element
10490     */
10491     fadeOut : function(o){
10492         var el = this.getFxEl();
10493         o = o || {};
10494         el.queueFx(o, function(){
10495             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10496                 o, null, .5, "easeOut", function(){
10497                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10498                      this.dom.style.display = "none";
10499                 }else{
10500                      this.dom.style.visibility = "hidden";
10501                 }
10502                 this.clearOpacity();
10503                 el.afterFx(o);
10504             });
10505         });
10506         return this;
10507     },
10508
10509    /**
10510     * Animates the transition of an element's dimensions from a starting height/width
10511     * to an ending height/width.
10512     * Usage:
10513 <pre><code>
10514 // change height and width to 100x100 pixels
10515 el.scale(100, 100);
10516
10517 // common config options shown with default values.  The height and width will default to
10518 // the element's existing values if passed as null.
10519 el.scale(
10520     [element's width],
10521     [element's height], {
10522     easing: 'easeOut',
10523     duration: .35
10524 });
10525 </code></pre>
10526     * @param {Number} width  The new width (pass undefined to keep the original width)
10527     * @param {Number} height  The new height (pass undefined to keep the original height)
10528     * @param {Object} options (optional) Object literal with any of the Fx config options
10529     * @return {Roo.Element} The Element
10530     */
10531     scale : function(w, h, o){
10532         this.shift(Roo.apply({}, o, {
10533             width: w,
10534             height: h
10535         }));
10536         return this;
10537     },
10538
10539    /**
10540     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10541     * Any of these properties not specified in the config object will not be changed.  This effect 
10542     * requires that at least one new dimension, position or opacity setting must be passed in on
10543     * the config object in order for the function to have any effect.
10544     * Usage:
10545 <pre><code>
10546 // slide the element horizontally to x position 200 while changing the height and opacity
10547 el.shift({ x: 200, height: 50, opacity: .8 });
10548
10549 // common config options shown with default values.
10550 el.shift({
10551     width: [element's width],
10552     height: [element's height],
10553     x: [element's x position],
10554     y: [element's y position],
10555     opacity: [element's opacity],
10556     easing: 'easeOut',
10557     duration: .35
10558 });
10559 </code></pre>
10560     * @param {Object} options  Object literal with any of the Fx config options
10561     * @return {Roo.Element} The Element
10562     */
10563     shift : function(o){
10564         var el = this.getFxEl();
10565         o = o || {};
10566         el.queueFx(o, function(){
10567             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10568             if(w !== undefined){
10569                 a.width = {to: this.adjustWidth(w)};
10570             }
10571             if(h !== undefined){
10572                 a.height = {to: this.adjustHeight(h)};
10573             }
10574             if(x !== undefined || y !== undefined){
10575                 a.points = {to: [
10576                     x !== undefined ? x : this.getX(),
10577                     y !== undefined ? y : this.getY()
10578                 ]};
10579             }
10580             if(op !== undefined){
10581                 a.opacity = {to: op};
10582             }
10583             if(o.xy !== undefined){
10584                 a.points = {to: o.xy};
10585             }
10586             arguments.callee.anim = this.fxanim(a,
10587                 o, 'motion', .35, "easeOut", function(){
10588                 el.afterFx(o);
10589             });
10590         });
10591         return this;
10592     },
10593
10594         /**
10595          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10596          * ending point of the effect.
10597          * Usage:
10598          *<pre><code>
10599 // default: slide the element downward while fading out
10600 el.ghost();
10601
10602 // custom: slide the element out to the right with a 2-second duration
10603 el.ghost('r', { duration: 2 });
10604
10605 // common config options shown with default values
10606 el.ghost('b', {
10607     easing: 'easeOut',
10608     duration: .5
10609     remove: false,
10610     useDisplay: false
10611 });
10612 </code></pre>
10613          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10614          * @param {Object} options (optional) Object literal with any of the Fx config options
10615          * @return {Roo.Element} The Element
10616          */
10617     ghost : function(anchor, o){
10618         var el = this.getFxEl();
10619         o = o || {};
10620
10621         el.queueFx(o, function(){
10622             anchor = anchor || "b";
10623
10624             // restore values after effect
10625             var r = this.getFxRestore();
10626             var w = this.getWidth(),
10627                 h = this.getHeight();
10628
10629             var st = this.dom.style;
10630
10631             var after = function(){
10632                 if(o.useDisplay){
10633                     el.setDisplayed(false);
10634                 }else{
10635                     el.hide();
10636                 }
10637
10638                 el.clearOpacity();
10639                 el.setPositioning(r.pos);
10640                 st.width = r.width;
10641                 st.height = r.height;
10642
10643                 el.afterFx(o);
10644             };
10645
10646             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10647             switch(anchor.toLowerCase()){
10648                 case "t":
10649                     pt.by = [0, -h];
10650                 break;
10651                 case "l":
10652                     pt.by = [-w, 0];
10653                 break;
10654                 case "r":
10655                     pt.by = [w, 0];
10656                 break;
10657                 case "b":
10658                     pt.by = [0, h];
10659                 break;
10660                 case "tl":
10661                     pt.by = [-w, -h];
10662                 break;
10663                 case "bl":
10664                     pt.by = [-w, h];
10665                 break;
10666                 case "br":
10667                     pt.by = [w, h];
10668                 break;
10669                 case "tr":
10670                     pt.by = [w, -h];
10671                 break;
10672             }
10673
10674             arguments.callee.anim = this.fxanim(a,
10675                 o,
10676                 'motion',
10677                 .5,
10678                 "easeOut", after);
10679         });
10680         return this;
10681     },
10682
10683         /**
10684          * Ensures that all effects queued after syncFx is called on the element are
10685          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10686          * @return {Roo.Element} The Element
10687          */
10688     syncFx : function(){
10689         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10690             block : false,
10691             concurrent : true,
10692             stopFx : false
10693         });
10694         return this;
10695     },
10696
10697         /**
10698          * Ensures that all effects queued after sequenceFx is called on the element are
10699          * run in sequence.  This is the opposite of {@link #syncFx}.
10700          * @return {Roo.Element} The Element
10701          */
10702     sequenceFx : function(){
10703         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10704             block : false,
10705             concurrent : false,
10706             stopFx : false
10707         });
10708         return this;
10709     },
10710
10711         /* @private */
10712     nextFx : function(){
10713         var ef = this.fxQueue[0];
10714         if(ef){
10715             ef.call(this);
10716         }
10717     },
10718
10719         /**
10720          * Returns true if the element has any effects actively running or queued, else returns false.
10721          * @return {Boolean} True if element has active effects, else false
10722          */
10723     hasActiveFx : function(){
10724         return this.fxQueue && this.fxQueue[0];
10725     },
10726
10727         /**
10728          * Stops any running effects and clears the element's internal effects queue if it contains
10729          * any additional effects that haven't started yet.
10730          * @return {Roo.Element} The Element
10731          */
10732     stopFx : function(){
10733         if(this.hasActiveFx()){
10734             var cur = this.fxQueue[0];
10735             if(cur && cur.anim && cur.anim.isAnimated()){
10736                 this.fxQueue = [cur]; // clear out others
10737                 cur.anim.stop(true);
10738             }
10739         }
10740         return this;
10741     },
10742
10743         /* @private */
10744     beforeFx : function(o){
10745         if(this.hasActiveFx() && !o.concurrent){
10746            if(o.stopFx){
10747                this.stopFx();
10748                return true;
10749            }
10750            return false;
10751         }
10752         return true;
10753     },
10754
10755         /**
10756          * Returns true if the element is currently blocking so that no other effect can be queued
10757          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10758          * used to ensure that an effect initiated by a user action runs to completion prior to the
10759          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10760          * @return {Boolean} True if blocking, else false
10761          */
10762     hasFxBlock : function(){
10763         var q = this.fxQueue;
10764         return q && q[0] && q[0].block;
10765     },
10766
10767         /* @private */
10768     queueFx : function(o, fn){
10769         if(!this.fxQueue){
10770             this.fxQueue = [];
10771         }
10772         if(!this.hasFxBlock()){
10773             Roo.applyIf(o, this.fxDefaults);
10774             if(!o.concurrent){
10775                 var run = this.beforeFx(o);
10776                 fn.block = o.block;
10777                 this.fxQueue.push(fn);
10778                 if(run){
10779                     this.nextFx();
10780                 }
10781             }else{
10782                 fn.call(this);
10783             }
10784         }
10785         return this;
10786     },
10787
10788         /* @private */
10789     fxWrap : function(pos, o, vis){
10790         var wrap;
10791         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10792             var wrapXY;
10793             if(o.fixPosition){
10794                 wrapXY = this.getXY();
10795             }
10796             var div = document.createElement("div");
10797             div.style.visibility = vis;
10798             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10799             wrap.setPositioning(pos);
10800             if(wrap.getStyle("position") == "static"){
10801                 wrap.position("relative");
10802             }
10803             this.clearPositioning('auto');
10804             wrap.clip();
10805             wrap.dom.appendChild(this.dom);
10806             if(wrapXY){
10807                 wrap.setXY(wrapXY);
10808             }
10809         }
10810         return wrap;
10811     },
10812
10813         /* @private */
10814     fxUnwrap : function(wrap, pos, o){
10815         this.clearPositioning();
10816         this.setPositioning(pos);
10817         if(!o.wrap){
10818             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10819             wrap.remove();
10820         }
10821     },
10822
10823         /* @private */
10824     getFxRestore : function(){
10825         var st = this.dom.style;
10826         return {pos: this.getPositioning(), width: st.width, height : st.height};
10827     },
10828
10829         /* @private */
10830     afterFx : function(o){
10831         if(o.afterStyle){
10832             this.applyStyles(o.afterStyle);
10833         }
10834         if(o.afterCls){
10835             this.addClass(o.afterCls);
10836         }
10837         if(o.remove === true){
10838             this.remove();
10839         }
10840         Roo.callback(o.callback, o.scope, [this]);
10841         if(!o.concurrent){
10842             this.fxQueue.shift();
10843             this.nextFx();
10844         }
10845     },
10846
10847         /* @private */
10848     getFxEl : function(){ // support for composite element fx
10849         return Roo.get(this.dom);
10850     },
10851
10852         /* @private */
10853     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10854         animType = animType || 'run';
10855         opt = opt || {};
10856         var anim = Roo.lib.Anim[animType](
10857             this.dom, args,
10858             (opt.duration || defaultDur) || .35,
10859             (opt.easing || defaultEase) || 'easeOut',
10860             function(){
10861                 Roo.callback(cb, this);
10862             },
10863             this
10864         );
10865         opt.anim = anim;
10866         return anim;
10867     }
10868 };
10869
10870 // backwords compat
10871 Roo.Fx.resize = Roo.Fx.scale;
10872
10873 //When included, Roo.Fx is automatically applied to Element so that all basic
10874 //effects are available directly via the Element API
10875 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10876  * Based on:
10877  * Ext JS Library 1.1.1
10878  * Copyright(c) 2006-2007, Ext JS, LLC.
10879  *
10880  * Originally Released Under LGPL - original licence link has changed is not relivant.
10881  *
10882  * Fork - LGPL
10883  * <script type="text/javascript">
10884  */
10885
10886
10887 /**
10888  * @class Roo.CompositeElement
10889  * Standard composite class. Creates a Roo.Element for every element in the collection.
10890  * <br><br>
10891  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10892  * actions will be performed on all the elements in this collection.</b>
10893  * <br><br>
10894  * All methods return <i>this</i> and can be chained.
10895  <pre><code>
10896  var els = Roo.select("#some-el div.some-class", true);
10897  // or select directly from an existing element
10898  var el = Roo.get('some-el');
10899  el.select('div.some-class', true);
10900
10901  els.setWidth(100); // all elements become 100 width
10902  els.hide(true); // all elements fade out and hide
10903  // or
10904  els.setWidth(100).hide(true);
10905  </code></pre>
10906  */
10907 Roo.CompositeElement = function(els){
10908     this.elements = [];
10909     this.addElements(els);
10910 };
10911 Roo.CompositeElement.prototype = {
10912     isComposite: true,
10913     addElements : function(els){
10914         if(!els) return this;
10915         if(typeof els == "string"){
10916             els = Roo.Element.selectorFunction(els);
10917         }
10918         var yels = this.elements;
10919         var index = yels.length-1;
10920         for(var i = 0, len = els.length; i < len; i++) {
10921                 yels[++index] = Roo.get(els[i]);
10922         }
10923         return this;
10924     },
10925
10926     /**
10927     * Clears this composite and adds the elements returned by the passed selector.
10928     * @param {String/Array} els A string CSS selector, an array of elements or an element
10929     * @return {CompositeElement} this
10930     */
10931     fill : function(els){
10932         this.elements = [];
10933         this.add(els);
10934         return this;
10935     },
10936
10937     /**
10938     * Filters this composite to only elements that match the passed selector.
10939     * @param {String} selector A string CSS selector
10940     * @return {CompositeElement} this
10941     */
10942     filter : function(selector){
10943         var els = [];
10944         this.each(function(el){
10945             if(el.is(selector)){
10946                 els[els.length] = el.dom;
10947             }
10948         });
10949         this.fill(els);
10950         return this;
10951     },
10952
10953     invoke : function(fn, args){
10954         var els = this.elements;
10955         for(var i = 0, len = els.length; i < len; i++) {
10956                 Roo.Element.prototype[fn].apply(els[i], args);
10957         }
10958         return this;
10959     },
10960     /**
10961     * Adds elements to this composite.
10962     * @param {String/Array} els A string CSS selector, an array of elements or an element
10963     * @return {CompositeElement} this
10964     */
10965     add : function(els){
10966         if(typeof els == "string"){
10967             this.addElements(Roo.Element.selectorFunction(els));
10968         }else if(els.length !== undefined){
10969             this.addElements(els);
10970         }else{
10971             this.addElements([els]);
10972         }
10973         return this;
10974     },
10975     /**
10976     * Calls the passed function passing (el, this, index) for each element in this composite.
10977     * @param {Function} fn The function to call
10978     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10979     * @return {CompositeElement} this
10980     */
10981     each : function(fn, scope){
10982         var els = this.elements;
10983         for(var i = 0, len = els.length; i < len; i++){
10984             if(fn.call(scope || els[i], els[i], this, i) === false) {
10985                 break;
10986             }
10987         }
10988         return this;
10989     },
10990
10991     /**
10992      * Returns the Element object at the specified index
10993      * @param {Number} index
10994      * @return {Roo.Element}
10995      */
10996     item : function(index){
10997         return this.elements[index] || null;
10998     },
10999
11000     /**
11001      * Returns the first Element
11002      * @return {Roo.Element}
11003      */
11004     first : function(){
11005         return this.item(0);
11006     },
11007
11008     /**
11009      * Returns the last Element
11010      * @return {Roo.Element}
11011      */
11012     last : function(){
11013         return this.item(this.elements.length-1);
11014     },
11015
11016     /**
11017      * Returns the number of elements in this composite
11018      * @return Number
11019      */
11020     getCount : function(){
11021         return this.elements.length;
11022     },
11023
11024     /**
11025      * Returns true if this composite contains the passed element
11026      * @return Boolean
11027      */
11028     contains : function(el){
11029         return this.indexOf(el) !== -1;
11030     },
11031
11032     /**
11033      * Returns true if this composite contains the passed element
11034      * @return Boolean
11035      */
11036     indexOf : function(el){
11037         return this.elements.indexOf(Roo.get(el));
11038     },
11039
11040
11041     /**
11042     * Removes the specified element(s).
11043     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11044     * or an array of any of those.
11045     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11046     * @return {CompositeElement} this
11047     */
11048     removeElement : function(el, removeDom){
11049         if(el instanceof Array){
11050             for(var i = 0, len = el.length; i < len; i++){
11051                 this.removeElement(el[i]);
11052             }
11053             return this;
11054         }
11055         var index = typeof el == 'number' ? el : this.indexOf(el);
11056         if(index !== -1){
11057             if(removeDom){
11058                 var d = this.elements[index];
11059                 if(d.dom){
11060                     d.remove();
11061                 }else{
11062                     d.parentNode.removeChild(d);
11063                 }
11064             }
11065             this.elements.splice(index, 1);
11066         }
11067         return this;
11068     },
11069
11070     /**
11071     * Replaces the specified element with the passed element.
11072     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11073     * to replace.
11074     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11075     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11076     * @return {CompositeElement} this
11077     */
11078     replaceElement : function(el, replacement, domReplace){
11079         var index = typeof el == 'number' ? el : this.indexOf(el);
11080         if(index !== -1){
11081             if(domReplace){
11082                 this.elements[index].replaceWith(replacement);
11083             }else{
11084                 this.elements.splice(index, 1, Roo.get(replacement))
11085             }
11086         }
11087         return this;
11088     },
11089
11090     /**
11091      * Removes all elements.
11092      */
11093     clear : function(){
11094         this.elements = [];
11095     }
11096 };
11097 (function(){
11098     Roo.CompositeElement.createCall = function(proto, fnName){
11099         if(!proto[fnName]){
11100             proto[fnName] = function(){
11101                 return this.invoke(fnName, arguments);
11102             };
11103         }
11104     };
11105     for(var fnName in Roo.Element.prototype){
11106         if(typeof Roo.Element.prototype[fnName] == "function"){
11107             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11108         }
11109     };
11110 })();
11111 /*
11112  * Based on:
11113  * Ext JS Library 1.1.1
11114  * Copyright(c) 2006-2007, Ext JS, LLC.
11115  *
11116  * Originally Released Under LGPL - original licence link has changed is not relivant.
11117  *
11118  * Fork - LGPL
11119  * <script type="text/javascript">
11120  */
11121
11122 /**
11123  * @class Roo.CompositeElementLite
11124  * @extends Roo.CompositeElement
11125  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11126  <pre><code>
11127  var els = Roo.select("#some-el div.some-class");
11128  // or select directly from an existing element
11129  var el = Roo.get('some-el');
11130  el.select('div.some-class');
11131
11132  els.setWidth(100); // all elements become 100 width
11133  els.hide(true); // all elements fade out and hide
11134  // or
11135  els.setWidth(100).hide(true);
11136  </code></pre><br><br>
11137  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11138  * actions will be performed on all the elements in this collection.</b>
11139  */
11140 Roo.CompositeElementLite = function(els){
11141     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11142     this.el = new Roo.Element.Flyweight();
11143 };
11144 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11145     addElements : function(els){
11146         if(els){
11147             if(els instanceof Array){
11148                 this.elements = this.elements.concat(els);
11149             }else{
11150                 var yels = this.elements;
11151                 var index = yels.length-1;
11152                 for(var i = 0, len = els.length; i < len; i++) {
11153                     yels[++index] = els[i];
11154                 }
11155             }
11156         }
11157         return this;
11158     },
11159     invoke : function(fn, args){
11160         var els = this.elements;
11161         var el = this.el;
11162         for(var i = 0, len = els.length; i < len; i++) {
11163             el.dom = els[i];
11164                 Roo.Element.prototype[fn].apply(el, args);
11165         }
11166         return this;
11167     },
11168     /**
11169      * Returns a flyweight Element of the dom element object at the specified index
11170      * @param {Number} index
11171      * @return {Roo.Element}
11172      */
11173     item : function(index){
11174         if(!this.elements[index]){
11175             return null;
11176         }
11177         this.el.dom = this.elements[index];
11178         return this.el;
11179     },
11180
11181     // fixes scope with flyweight
11182     addListener : function(eventName, handler, scope, opt){
11183         var els = this.elements;
11184         for(var i = 0, len = els.length; i < len; i++) {
11185             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11186         }
11187         return this;
11188     },
11189
11190     /**
11191     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11192     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11193     * a reference to the dom node, use el.dom.</b>
11194     * @param {Function} fn The function to call
11195     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11196     * @return {CompositeElement} this
11197     */
11198     each : function(fn, scope){
11199         var els = this.elements;
11200         var el = this.el;
11201         for(var i = 0, len = els.length; i < len; i++){
11202             el.dom = els[i];
11203                 if(fn.call(scope || el, el, this, i) === false){
11204                 break;
11205             }
11206         }
11207         return this;
11208     },
11209
11210     indexOf : function(el){
11211         return this.elements.indexOf(Roo.getDom(el));
11212     },
11213
11214     replaceElement : function(el, replacement, domReplace){
11215         var index = typeof el == 'number' ? el : this.indexOf(el);
11216         if(index !== -1){
11217             replacement = Roo.getDom(replacement);
11218             if(domReplace){
11219                 var d = this.elements[index];
11220                 d.parentNode.insertBefore(replacement, d);
11221                 d.parentNode.removeChild(d);
11222             }
11223             this.elements.splice(index, 1, replacement);
11224         }
11225         return this;
11226     }
11227 });
11228 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11229
11230 /*
11231  * Based on:
11232  * Ext JS Library 1.1.1
11233  * Copyright(c) 2006-2007, Ext JS, LLC.
11234  *
11235  * Originally Released Under LGPL - original licence link has changed is not relivant.
11236  *
11237  * Fork - LGPL
11238  * <script type="text/javascript">
11239  */
11240
11241  
11242
11243 /**
11244  * @class Roo.data.Connection
11245  * @extends Roo.util.Observable
11246  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11247  * either to a configured URL, or to a URL specified at request time.<br><br>
11248  * <p>
11249  * Requests made by this class are asynchronous, and will return immediately. No data from
11250  * the server will be available to the statement immediately following the {@link #request} call.
11251  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11252  * <p>
11253  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11254  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11255  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11256  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11257  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11258  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11259  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11260  * standard DOM methods.
11261  * @constructor
11262  * @param {Object} config a configuration object.
11263  */
11264 Roo.data.Connection = function(config){
11265     Roo.apply(this, config);
11266     this.addEvents({
11267         /**
11268          * @event beforerequest
11269          * Fires before a network request is made to retrieve a data object.
11270          * @param {Connection} conn This Connection object.
11271          * @param {Object} options The options config object passed to the {@link #request} method.
11272          */
11273         "beforerequest" : true,
11274         /**
11275          * @event requestcomplete
11276          * Fires if the request was successfully completed.
11277          * @param {Connection} conn This Connection object.
11278          * @param {Object} response The XHR object containing the response data.
11279          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11280          * @param {Object} options The options config object passed to the {@link #request} method.
11281          */
11282         "requestcomplete" : true,
11283         /**
11284          * @event requestexception
11285          * Fires if an error HTTP status was returned from the server.
11286          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11287          * @param {Connection} conn This Connection object.
11288          * @param {Object} response The XHR object containing the response data.
11289          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11290          * @param {Object} options The options config object passed to the {@link #request} method.
11291          */
11292         "requestexception" : true
11293     });
11294     Roo.data.Connection.superclass.constructor.call(this);
11295 };
11296
11297 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11298     /**
11299      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11300      */
11301     /**
11302      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11303      * extra parameters to each request made by this object. (defaults to undefined)
11304      */
11305     /**
11306      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11307      *  to each request made by this object. (defaults to undefined)
11308      */
11309     /**
11310      * @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)
11311      */
11312     /**
11313      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11314      */
11315     timeout : 30000,
11316     /**
11317      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11318      * @type Boolean
11319      */
11320     autoAbort:false,
11321
11322     /**
11323      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11324      * @type Boolean
11325      */
11326     disableCaching: true,
11327
11328     /**
11329      * Sends an HTTP request to a remote server.
11330      * @param {Object} options An object which may contain the following properties:<ul>
11331      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11332      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11333      * request, a url encoded string or a function to call to get either.</li>
11334      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11335      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11336      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11337      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11338      * <li>options {Object} The parameter to the request call.</li>
11339      * <li>success {Boolean} True if the request succeeded.</li>
11340      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11341      * </ul></li>
11342      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11343      * The callback is passed the following parameters:<ul>
11344      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11345      * <li>options {Object} The parameter to the request call.</li>
11346      * </ul></li>
11347      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11348      * The callback is passed the following parameters:<ul>
11349      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11350      * <li>options {Object} The parameter to the request call.</li>
11351      * </ul></li>
11352      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11353      * for the callback function. Defaults to the browser window.</li>
11354      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11355      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11356      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11357      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11358      * params for the post data. Any params will be appended to the URL.</li>
11359      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11360      * </ul>
11361      * @return {Number} transactionId
11362      */
11363     request : function(o){
11364         if(this.fireEvent("beforerequest", this, o) !== false){
11365             var p = o.params;
11366
11367             if(typeof p == "function"){
11368                 p = p.call(o.scope||window, o);
11369             }
11370             if(typeof p == "object"){
11371                 p = Roo.urlEncode(o.params);
11372             }
11373             if(this.extraParams){
11374                 var extras = Roo.urlEncode(this.extraParams);
11375                 p = p ? (p + '&' + extras) : extras;
11376             }
11377
11378             var url = o.url || this.url;
11379             if(typeof url == 'function'){
11380                 url = url.call(o.scope||window, o);
11381             }
11382
11383             if(o.form){
11384                 var form = Roo.getDom(o.form);
11385                 url = url || form.action;
11386
11387                 var enctype = form.getAttribute("enctype");
11388                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11389                     return this.doFormUpload(o, p, url);
11390                 }
11391                 var f = Roo.lib.Ajax.serializeForm(form);
11392                 p = p ? (p + '&' + f) : f;
11393             }
11394
11395             var hs = o.headers;
11396             if(this.defaultHeaders){
11397                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11398                 if(!o.headers){
11399                     o.headers = hs;
11400                 }
11401             }
11402
11403             var cb = {
11404                 success: this.handleResponse,
11405                 failure: this.handleFailure,
11406                 scope: this,
11407                 argument: {options: o},
11408                 timeout : o.timeout || this.timeout
11409             };
11410
11411             var method = o.method||this.method||(p ? "POST" : "GET");
11412
11413             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11414                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11415             }
11416
11417             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11418                 if(o.autoAbort){
11419                     this.abort();
11420                 }
11421             }else if(this.autoAbort !== false){
11422                 this.abort();
11423             }
11424
11425             if((method == 'GET' && p) || o.xmlData){
11426                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11427                 p = '';
11428             }
11429             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11430             return this.transId;
11431         }else{
11432             Roo.callback(o.callback, o.scope, [o, null, null]);
11433             return null;
11434         }
11435     },
11436
11437     /**
11438      * Determine whether this object has a request outstanding.
11439      * @param {Number} transactionId (Optional) defaults to the last transaction
11440      * @return {Boolean} True if there is an outstanding request.
11441      */
11442     isLoading : function(transId){
11443         if(transId){
11444             return Roo.lib.Ajax.isCallInProgress(transId);
11445         }else{
11446             return this.transId ? true : false;
11447         }
11448     },
11449
11450     /**
11451      * Aborts any outstanding request.
11452      * @param {Number} transactionId (Optional) defaults to the last transaction
11453      */
11454     abort : function(transId){
11455         if(transId || this.isLoading()){
11456             Roo.lib.Ajax.abort(transId || this.transId);
11457         }
11458     },
11459
11460     // private
11461     handleResponse : function(response){
11462         this.transId = false;
11463         var options = response.argument.options;
11464         response.argument = options ? options.argument : null;
11465         this.fireEvent("requestcomplete", this, response, options);
11466         Roo.callback(options.success, options.scope, [response, options]);
11467         Roo.callback(options.callback, options.scope, [options, true, response]);
11468     },
11469
11470     // private
11471     handleFailure : function(response, e){
11472         this.transId = false;
11473         var options = response.argument.options;
11474         response.argument = options ? options.argument : null;
11475         this.fireEvent("requestexception", this, response, options, e);
11476         Roo.callback(options.failure, options.scope, [response, options]);
11477         Roo.callback(options.callback, options.scope, [options, false, response]);
11478     },
11479
11480     // private
11481     doFormUpload : function(o, ps, url){
11482         var id = Roo.id();
11483         var frame = document.createElement('iframe');
11484         frame.id = id;
11485         frame.name = id;
11486         frame.className = 'x-hidden';
11487         if(Roo.isIE){
11488             frame.src = Roo.SSL_SECURE_URL;
11489         }
11490         document.body.appendChild(frame);
11491
11492         if(Roo.isIE){
11493            document.frames[id].name = id;
11494         }
11495
11496         var form = Roo.getDom(o.form);
11497         form.target = id;
11498         form.method = 'POST';
11499         form.enctype = form.encoding = 'multipart/form-data';
11500         if(url){
11501             form.action = url;
11502         }
11503
11504         var hiddens, hd;
11505         if(ps){ // add dynamic params
11506             hiddens = [];
11507             ps = Roo.urlDecode(ps, false);
11508             for(var k in ps){
11509                 if(ps.hasOwnProperty(k)){
11510                     hd = document.createElement('input');
11511                     hd.type = 'hidden';
11512                     hd.name = k;
11513                     hd.value = ps[k];
11514                     form.appendChild(hd);
11515                     hiddens.push(hd);
11516                 }
11517             }
11518         }
11519
11520         function cb(){
11521             var r = {  // bogus response object
11522                 responseText : '',
11523                 responseXML : null
11524             };
11525
11526             r.argument = o ? o.argument : null;
11527
11528             try { //
11529                 var doc;
11530                 if(Roo.isIE){
11531                     doc = frame.contentWindow.document;
11532                 }else {
11533                     doc = (frame.contentDocument || window.frames[id].document);
11534                 }
11535                 if(doc && doc.body){
11536                     r.responseText = doc.body.innerHTML;
11537                 }
11538                 if(doc && doc.XMLDocument){
11539                     r.responseXML = doc.XMLDocument;
11540                 }else {
11541                     r.responseXML = doc;
11542                 }
11543             }
11544             catch(e) {
11545                 // ignore
11546             }
11547
11548             Roo.EventManager.removeListener(frame, 'load', cb, this);
11549
11550             this.fireEvent("requestcomplete", this, r, o);
11551             Roo.callback(o.success, o.scope, [r, o]);
11552             Roo.callback(o.callback, o.scope, [o, true, r]);
11553
11554             setTimeout(function(){document.body.removeChild(frame);}, 100);
11555         }
11556
11557         Roo.EventManager.on(frame, 'load', cb, this);
11558         form.submit();
11559
11560         if(hiddens){ // remove dynamic params
11561             for(var i = 0, len = hiddens.length; i < len; i++){
11562                 form.removeChild(hiddens[i]);
11563             }
11564         }
11565     }
11566 });
11567 /*
11568  * Based on:
11569  * Ext JS Library 1.1.1
11570  * Copyright(c) 2006-2007, Ext JS, LLC.
11571  *
11572  * Originally Released Under LGPL - original licence link has changed is not relivant.
11573  *
11574  * Fork - LGPL
11575  * <script type="text/javascript">
11576  */
11577  
11578 /**
11579  * Global Ajax request class.
11580  * 
11581  * @class Roo.Ajax
11582  * @extends Roo.data.Connection
11583  * @static
11584  * 
11585  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11586  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11587  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11588  * @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)
11589  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11590  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11591  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11592  */
11593 Roo.Ajax = new Roo.data.Connection({
11594     // fix up the docs
11595     /**
11596      * @scope Roo.Ajax
11597      * @type {Boolear} 
11598      */
11599     autoAbort : false,
11600
11601     /**
11602      * Serialize the passed form into a url encoded string
11603      * @scope Roo.Ajax
11604      * @param {String/HTMLElement} form
11605      * @return {String}
11606      */
11607     serializeForm : function(form){
11608         return Roo.lib.Ajax.serializeForm(form);
11609     }
11610 });/*
11611  * Based on:
11612  * Ext JS Library 1.1.1
11613  * Copyright(c) 2006-2007, Ext JS, LLC.
11614  *
11615  * Originally Released Under LGPL - original licence link has changed is not relivant.
11616  *
11617  * Fork - LGPL
11618  * <script type="text/javascript">
11619  */
11620
11621  
11622 /**
11623  * @class Roo.UpdateManager
11624  * @extends Roo.util.Observable
11625  * Provides AJAX-style update for Element object.<br><br>
11626  * Usage:<br>
11627  * <pre><code>
11628  * // Get it from a Roo.Element object
11629  * var el = Roo.get("foo");
11630  * var mgr = el.getUpdateManager();
11631  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11632  * ...
11633  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11634  * <br>
11635  * // or directly (returns the same UpdateManager instance)
11636  * var mgr = new Roo.UpdateManager("myElementId");
11637  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11638  * mgr.on("update", myFcnNeedsToKnow);
11639  * <br>
11640    // short handed call directly from the element object
11641    Roo.get("foo").load({
11642         url: "bar.php",
11643         scripts:true,
11644         params: "for=bar",
11645         text: "Loading Foo..."
11646    });
11647  * </code></pre>
11648  * @constructor
11649  * Create new UpdateManager directly.
11650  * @param {String/HTMLElement/Roo.Element} el The element to update
11651  * @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).
11652  */
11653 Roo.UpdateManager = function(el, forceNew){
11654     el = Roo.get(el);
11655     if(!forceNew && el.updateManager){
11656         return el.updateManager;
11657     }
11658     /**
11659      * The Element object
11660      * @type Roo.Element
11661      */
11662     this.el = el;
11663     /**
11664      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11665      * @type String
11666      */
11667     this.defaultUrl = null;
11668
11669     this.addEvents({
11670         /**
11671          * @event beforeupdate
11672          * Fired before an update is made, return false from your handler and the update is cancelled.
11673          * @param {Roo.Element} el
11674          * @param {String/Object/Function} url
11675          * @param {String/Object} params
11676          */
11677         "beforeupdate": true,
11678         /**
11679          * @event update
11680          * Fired after successful update is made.
11681          * @param {Roo.Element} el
11682          * @param {Object} oResponseObject The response Object
11683          */
11684         "update": true,
11685         /**
11686          * @event failure
11687          * Fired on update failure.
11688          * @param {Roo.Element} el
11689          * @param {Object} oResponseObject The response Object
11690          */
11691         "failure": true
11692     });
11693     var d = Roo.UpdateManager.defaults;
11694     /**
11695      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11696      * @type String
11697      */
11698     this.sslBlankUrl = d.sslBlankUrl;
11699     /**
11700      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11701      * @type Boolean
11702      */
11703     this.disableCaching = d.disableCaching;
11704     /**
11705      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11706      * @type String
11707      */
11708     this.indicatorText = d.indicatorText;
11709     /**
11710      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11711      * @type String
11712      */
11713     this.showLoadIndicator = d.showLoadIndicator;
11714     /**
11715      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11716      * @type Number
11717      */
11718     this.timeout = d.timeout;
11719
11720     /**
11721      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11722      * @type Boolean
11723      */
11724     this.loadScripts = d.loadScripts;
11725
11726     /**
11727      * Transaction object of current executing transaction
11728      */
11729     this.transaction = null;
11730
11731     /**
11732      * @private
11733      */
11734     this.autoRefreshProcId = null;
11735     /**
11736      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11737      * @type Function
11738      */
11739     this.refreshDelegate = this.refresh.createDelegate(this);
11740     /**
11741      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11742      * @type Function
11743      */
11744     this.updateDelegate = this.update.createDelegate(this);
11745     /**
11746      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11747      * @type Function
11748      */
11749     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11750     /**
11751      * @private
11752      */
11753     this.successDelegate = this.processSuccess.createDelegate(this);
11754     /**
11755      * @private
11756      */
11757     this.failureDelegate = this.processFailure.createDelegate(this);
11758
11759     if(!this.renderer){
11760      /**
11761       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11762       */
11763     this.renderer = new Roo.UpdateManager.BasicRenderer();
11764     }
11765     
11766     Roo.UpdateManager.superclass.constructor.call(this);
11767 };
11768
11769 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11770     /**
11771      * Get the Element this UpdateManager is bound to
11772      * @return {Roo.Element} The element
11773      */
11774     getEl : function(){
11775         return this.el;
11776     },
11777     /**
11778      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11779      * @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:
11780 <pre><code>
11781 um.update({<br/>
11782     url: "your-url.php",<br/>
11783     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11784     callback: yourFunction,<br/>
11785     scope: yourObject, //(optional scope)  <br/>
11786     discardUrl: false, <br/>
11787     nocache: false,<br/>
11788     text: "Loading...",<br/>
11789     timeout: 30,<br/>
11790     scripts: false<br/>
11791 });
11792 </code></pre>
11793      * The only required property is url. The optional properties nocache, text and scripts
11794      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11795      * @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}
11796      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11797      * @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.
11798      */
11799     update : function(url, params, callback, discardUrl){
11800         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11801             var method = this.method,
11802                 cfg;
11803             if(typeof url == "object"){ // must be config object
11804                 cfg = url;
11805                 url = cfg.url;
11806                 params = params || cfg.params;
11807                 callback = callback || cfg.callback;
11808                 discardUrl = discardUrl || cfg.discardUrl;
11809                 if(callback && cfg.scope){
11810                     callback = callback.createDelegate(cfg.scope);
11811                 }
11812                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11813                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11814                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11815                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11816                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11817             }
11818             this.showLoading();
11819             if(!discardUrl){
11820                 this.defaultUrl = url;
11821             }
11822             if(typeof url == "function"){
11823                 url = url.call(this);
11824             }
11825
11826             method = method || (params ? "POST" : "GET");
11827             if(method == "GET"){
11828                 url = this.prepareUrl(url);
11829             }
11830
11831             var o = Roo.apply(cfg ||{}, {
11832                 url : url,
11833                 params: params,
11834                 success: this.successDelegate,
11835                 failure: this.failureDelegate,
11836                 callback: undefined,
11837                 timeout: (this.timeout*1000),
11838                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11839             });
11840             Roo.log("updated manager called with timeout of " + o.timeout);
11841             this.transaction = Roo.Ajax.request(o);
11842         }
11843     },
11844
11845     /**
11846      * 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.
11847      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11848      * @param {String/HTMLElement} form The form Id or form element
11849      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11850      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11851      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11852      */
11853     formUpdate : function(form, url, reset, callback){
11854         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11855             if(typeof url == "function"){
11856                 url = url.call(this);
11857             }
11858             form = Roo.getDom(form);
11859             this.transaction = Roo.Ajax.request({
11860                 form: form,
11861                 url:url,
11862                 success: this.successDelegate,
11863                 failure: this.failureDelegate,
11864                 timeout: (this.timeout*1000),
11865                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11866             });
11867             this.showLoading.defer(1, this);
11868         }
11869     },
11870
11871     /**
11872      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11873      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11874      */
11875     refresh : function(callback){
11876         if(this.defaultUrl == null){
11877             return;
11878         }
11879         this.update(this.defaultUrl, null, callback, true);
11880     },
11881
11882     /**
11883      * Set this element to auto refresh.
11884      * @param {Number} interval How often to update (in seconds).
11885      * @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)
11886      * @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}
11887      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11888      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11889      */
11890     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11891         if(refreshNow){
11892             this.update(url || this.defaultUrl, params, callback, true);
11893         }
11894         if(this.autoRefreshProcId){
11895             clearInterval(this.autoRefreshProcId);
11896         }
11897         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11898     },
11899
11900     /**
11901      * Stop auto refresh on this element.
11902      */
11903      stopAutoRefresh : function(){
11904         if(this.autoRefreshProcId){
11905             clearInterval(this.autoRefreshProcId);
11906             delete this.autoRefreshProcId;
11907         }
11908     },
11909
11910     isAutoRefreshing : function(){
11911        return this.autoRefreshProcId ? true : false;
11912     },
11913     /**
11914      * Called to update the element to "Loading" state. Override to perform custom action.
11915      */
11916     showLoading : function(){
11917         if(this.showLoadIndicator){
11918             this.el.update(this.indicatorText);
11919         }
11920     },
11921
11922     /**
11923      * Adds unique parameter to query string if disableCaching = true
11924      * @private
11925      */
11926     prepareUrl : function(url){
11927         if(this.disableCaching){
11928             var append = "_dc=" + (new Date().getTime());
11929             if(url.indexOf("?") !== -1){
11930                 url += "&" + append;
11931             }else{
11932                 url += "?" + append;
11933             }
11934         }
11935         return url;
11936     },
11937
11938     /**
11939      * @private
11940      */
11941     processSuccess : function(response){
11942         this.transaction = null;
11943         if(response.argument.form && response.argument.reset){
11944             try{ // put in try/catch since some older FF releases had problems with this
11945                 response.argument.form.reset();
11946             }catch(e){}
11947         }
11948         if(this.loadScripts){
11949             this.renderer.render(this.el, response, this,
11950                 this.updateComplete.createDelegate(this, [response]));
11951         }else{
11952             this.renderer.render(this.el, response, this);
11953             this.updateComplete(response);
11954         }
11955     },
11956
11957     updateComplete : function(response){
11958         this.fireEvent("update", this.el, response);
11959         if(typeof response.argument.callback == "function"){
11960             response.argument.callback(this.el, true, response);
11961         }
11962     },
11963
11964     /**
11965      * @private
11966      */
11967     processFailure : function(response){
11968         this.transaction = null;
11969         this.fireEvent("failure", this.el, response);
11970         if(typeof response.argument.callback == "function"){
11971             response.argument.callback(this.el, false, response);
11972         }
11973     },
11974
11975     /**
11976      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11977      * @param {Object} renderer The object implementing the render() method
11978      */
11979     setRenderer : function(renderer){
11980         this.renderer = renderer;
11981     },
11982
11983     getRenderer : function(){
11984        return this.renderer;
11985     },
11986
11987     /**
11988      * Set the defaultUrl used for updates
11989      * @param {String/Function} defaultUrl The url or a function to call to get the url
11990      */
11991     setDefaultUrl : function(defaultUrl){
11992         this.defaultUrl = defaultUrl;
11993     },
11994
11995     /**
11996      * Aborts the executing transaction
11997      */
11998     abort : function(){
11999         if(this.transaction){
12000             Roo.Ajax.abort(this.transaction);
12001         }
12002     },
12003
12004     /**
12005      * Returns true if an update is in progress
12006      * @return {Boolean}
12007      */
12008     isUpdating : function(){
12009         if(this.transaction){
12010             return Roo.Ajax.isLoading(this.transaction);
12011         }
12012         return false;
12013     }
12014 });
12015
12016 /**
12017  * @class Roo.UpdateManager.defaults
12018  * @static (not really - but it helps the doc tool)
12019  * The defaults collection enables customizing the default properties of UpdateManager
12020  */
12021    Roo.UpdateManager.defaults = {
12022        /**
12023          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12024          * @type Number
12025          */
12026          timeout : 30,
12027
12028          /**
12029          * True to process scripts by default (Defaults to false).
12030          * @type Boolean
12031          */
12032         loadScripts : false,
12033
12034         /**
12035         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12036         * @type String
12037         */
12038         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12039         /**
12040          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12041          * @type Boolean
12042          */
12043         disableCaching : false,
12044         /**
12045          * Whether to show indicatorText when loading (Defaults to true).
12046          * @type Boolean
12047          */
12048         showLoadIndicator : true,
12049         /**
12050          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12051          * @type String
12052          */
12053         indicatorText : '<div class="loading-indicator">Loading...</div>'
12054    };
12055
12056 /**
12057  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12058  *Usage:
12059  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12060  * @param {String/HTMLElement/Roo.Element} el The element to update
12061  * @param {String} url The url
12062  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12063  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12064  * @static
12065  * @deprecated
12066  * @member Roo.UpdateManager
12067  */
12068 Roo.UpdateManager.updateElement = function(el, url, params, options){
12069     var um = Roo.get(el, true).getUpdateManager();
12070     Roo.apply(um, options);
12071     um.update(url, params, options ? options.callback : null);
12072 };
12073 // alias for backwards compat
12074 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12075 /**
12076  * @class Roo.UpdateManager.BasicRenderer
12077  * Default Content renderer. Updates the elements innerHTML with the responseText.
12078  */
12079 Roo.UpdateManager.BasicRenderer = function(){};
12080
12081 Roo.UpdateManager.BasicRenderer.prototype = {
12082     /**
12083      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12084      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12085      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12086      * @param {Roo.Element} el The element being rendered
12087      * @param {Object} response The YUI Connect response object
12088      * @param {UpdateManager} updateManager The calling update manager
12089      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12090      */
12091      render : function(el, response, updateManager, callback){
12092         el.update(response.responseText, updateManager.loadScripts, callback);
12093     }
12094 };
12095 /*
12096  * Based on:
12097  * Roo JS
12098  * (c)) Alan Knowles
12099  * Licence : LGPL
12100  */
12101
12102
12103 /**
12104  * @class Roo.DomTemplate
12105  * @extends Roo.Template
12106  * An effort at a dom based template engine..
12107  *
12108  * Similar to XTemplate, except it uses dom parsing to create the template..
12109  *
12110  * Supported features:
12111  *
12112  *  Tags:
12113
12114 <pre><code>
12115       {a_variable} - output encoded.
12116       {a_variable.format:("Y-m-d")} - call a method on the variable
12117       {a_variable:raw} - unencoded output
12118       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12119       {a_variable:this.method_on_template(...)} - call a method on the template object.
12120  
12121 </code></pre>
12122  *  The tpl tag:
12123 <pre><code>
12124         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12125         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12126         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12127         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12128   
12129 </code></pre>
12130  *      
12131  */
12132 Roo.DomTemplate = function()
12133 {
12134      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12135      if (this.html) {
12136         this.compile();
12137      }
12138 };
12139
12140
12141 Roo.extend(Roo.DomTemplate, Roo.Template, {
12142     /**
12143      * id counter for sub templates.
12144      */
12145     id : 0,
12146     /**
12147      * flag to indicate if dom parser is inside a pre,
12148      * it will strip whitespace if not.
12149      */
12150     inPre : false,
12151     
12152     /**
12153      * The various sub templates
12154      */
12155     tpls : false,
12156     
12157     
12158     
12159     /**
12160      *
12161      * basic tag replacing syntax
12162      * WORD:WORD()
12163      *
12164      * // you can fake an object call by doing this
12165      *  x.t:(test,tesT) 
12166      * 
12167      */
12168     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12169     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12170     
12171     iterChild : function (node, method) {
12172         
12173         var oldPre = this.inPre;
12174         if (node.tagName == 'PRE') {
12175             this.inPre = true;
12176         }
12177         for( var i = 0; i < node.childNodes.length; i++) {
12178             method.call(this, node.childNodes[i]);
12179         }
12180         this.inPre = oldPre;
12181     },
12182     
12183     
12184     
12185     /**
12186      * compile the template
12187      *
12188      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12189      *
12190      */
12191     compile: function()
12192     {
12193         var s = this.html;
12194         
12195         // covert the html into DOM...
12196         var doc = false;
12197         var div =false;
12198         try {
12199             doc = document.implementation.createHTMLDocument("");
12200             doc.documentElement.innerHTML =   this.html  ;
12201             div = doc.documentElement;
12202         } catch (e) {
12203             // old IE... - nasty -- it causes all sorts of issues.. with
12204             // images getting pulled from server..
12205             div = document.createElement('div');
12206             div.innerHTML = this.html;
12207         }
12208         //doc.documentElement.innerHTML = htmlBody
12209          
12210         
12211         
12212         this.tpls = [];
12213         var _t = this;
12214         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12215         
12216         var tpls = this.tpls;
12217         
12218         // create a top level template from the snippet..
12219         
12220         //Roo.log(div.innerHTML);
12221         
12222         var tpl = {
12223             uid : 'master',
12224             id : this.id++,
12225             attr : false,
12226             value : false,
12227             body : div.innerHTML,
12228             
12229             forCall : false,
12230             execCall : false,
12231             dom : div,
12232             isTop : true
12233             
12234         };
12235         tpls.unshift(tpl);
12236         
12237         
12238         // compile them...
12239         this.tpls = [];
12240         Roo.each(tpls, function(tp){
12241             this.compileTpl(tp);
12242             this.tpls[tp.id] = tp;
12243         }, this);
12244         
12245         this.master = tpls[0];
12246         return this;
12247         
12248         
12249     },
12250     
12251     compileNode : function(node, istop) {
12252         // test for
12253         //Roo.log(node);
12254         
12255         
12256         // skip anything not a tag..
12257         if (node.nodeType != 1) {
12258             if (node.nodeType == 3 && !this.inPre) {
12259                 // reduce white space..
12260                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12261                 
12262             }
12263             return;
12264         }
12265         
12266         var tpl = {
12267             uid : false,
12268             id : false,
12269             attr : false,
12270             value : false,
12271             body : '',
12272             
12273             forCall : false,
12274             execCall : false,
12275             dom : false,
12276             isTop : istop
12277             
12278             
12279         };
12280         
12281         
12282         switch(true) {
12283             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12284             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12285             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12286             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12287             // no default..
12288         }
12289         
12290         
12291         if (!tpl.attr) {
12292             // just itterate children..
12293             this.iterChild(node,this.compileNode);
12294             return;
12295         }
12296         tpl.uid = this.id++;
12297         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12298         node.removeAttribute('roo-'+ tpl.attr);
12299         if (tpl.attr != 'name') {
12300             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12301             node.parentNode.replaceChild(placeholder,  node);
12302         } else {
12303             
12304             var placeholder =  document.createElement('span');
12305             placeholder.className = 'roo-tpl-' + tpl.value;
12306             node.parentNode.replaceChild(placeholder,  node);
12307         }
12308         
12309         // parent now sees '{domtplXXXX}
12310         this.iterChild(node,this.compileNode);
12311         
12312         // we should now have node body...
12313         var div = document.createElement('div');
12314         div.appendChild(node);
12315         tpl.dom = node;
12316         // this has the unfortunate side effect of converting tagged attributes
12317         // eg. href="{...}" into %7C...%7D
12318         // this has been fixed by searching for those combo's although it's a bit hacky..
12319         
12320         
12321         tpl.body = div.innerHTML;
12322         
12323         
12324          
12325         tpl.id = tpl.uid;
12326         switch(tpl.attr) {
12327             case 'for' :
12328                 switch (tpl.value) {
12329                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12330                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12331                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12332                 }
12333                 break;
12334             
12335             case 'exec':
12336                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12337                 break;
12338             
12339             case 'if':     
12340                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12341                 break;
12342             
12343             case 'name':
12344                 tpl.id  = tpl.value; // replace non characters???
12345                 break;
12346             
12347         }
12348         
12349         
12350         this.tpls.push(tpl);
12351         
12352         
12353         
12354     },
12355     
12356     
12357     
12358     
12359     /**
12360      * Compile a segment of the template into a 'sub-template'
12361      *
12362      * 
12363      * 
12364      *
12365      */
12366     compileTpl : function(tpl)
12367     {
12368         var fm = Roo.util.Format;
12369         var useF = this.disableFormats !== true;
12370         
12371         var sep = Roo.isGecko ? "+\n" : ",\n";
12372         
12373         var undef = function(str) {
12374             Roo.debug && Roo.log("Property not found :"  + str);
12375             return '';
12376         };
12377           
12378         //Roo.log(tpl.body);
12379         
12380         
12381         
12382         var fn = function(m, lbrace, name, format, args)
12383         {
12384             //Roo.log("ARGS");
12385             //Roo.log(arguments);
12386             args = args ? args.replace(/\\'/g,"'") : args;
12387             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12388             if (typeof(format) == 'undefined') {
12389                 format =  'htmlEncode'; 
12390             }
12391             if (format == 'raw' ) {
12392                 format = false;
12393             }
12394             
12395             if(name.substr(0, 6) == 'domtpl'){
12396                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12397             }
12398             
12399             // build an array of options to determine if value is undefined..
12400             
12401             // basically get 'xxxx.yyyy' then do
12402             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12403             //    (function () { Roo.log("Property not found"); return ''; })() :
12404             //    ......
12405             
12406             var udef_ar = [];
12407             var lookfor = '';
12408             Roo.each(name.split('.'), function(st) {
12409                 lookfor += (lookfor.length ? '.': '') + st;
12410                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12411             });
12412             
12413             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12414             
12415             
12416             if(format && useF){
12417                 
12418                 args = args ? ',' + args : "";
12419                  
12420                 if(format.substr(0, 5) != "this."){
12421                     format = "fm." + format + '(';
12422                 }else{
12423                     format = 'this.call("'+ format.substr(5) + '", ';
12424                     args = ", values";
12425                 }
12426                 
12427                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12428             }
12429              
12430             if (args.length) {
12431                 // called with xxyx.yuu:(test,test)
12432                 // change to ()
12433                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12434             }
12435             // raw.. - :raw modifier..
12436             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12437             
12438         };
12439         var body;
12440         // branched to use + in gecko and [].join() in others
12441         if(Roo.isGecko){
12442             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12443                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12444                     "';};};";
12445         }else{
12446             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12447             body.push(tpl.body.replace(/(\r\n|\n)/g,
12448                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12449             body.push("'].join('');};};");
12450             body = body.join('');
12451         }
12452         
12453         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12454        
12455         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12456         eval(body);
12457         
12458         return this;
12459     },
12460      
12461     /**
12462      * same as applyTemplate, except it's done to one of the subTemplates
12463      * when using named templates, you can do:
12464      *
12465      * var str = pl.applySubTemplate('your-name', values);
12466      *
12467      * 
12468      * @param {Number} id of the template
12469      * @param {Object} values to apply to template
12470      * @param {Object} parent (normaly the instance of this object)
12471      */
12472     applySubTemplate : function(id, values, parent)
12473     {
12474         
12475         
12476         var t = this.tpls[id];
12477         
12478         
12479         try { 
12480             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12481                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12482                 return '';
12483             }
12484         } catch(e) {
12485             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12486             Roo.log(values);
12487           
12488             return '';
12489         }
12490         try { 
12491             
12492             if(t.execCall && t.execCall.call(this, values, parent)){
12493                 return '';
12494             }
12495         } catch(e) {
12496             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12497             Roo.log(values);
12498             return '';
12499         }
12500         
12501         try {
12502             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12503             parent = t.target ? values : parent;
12504             if(t.forCall && vs instanceof Array){
12505                 var buf = [];
12506                 for(var i = 0, len = vs.length; i < len; i++){
12507                     try {
12508                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12509                     } catch (e) {
12510                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12511                         Roo.log(e.body);
12512                         //Roo.log(t.compiled);
12513                         Roo.log(vs[i]);
12514                     }   
12515                 }
12516                 return buf.join('');
12517             }
12518         } catch (e) {
12519             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12520             Roo.log(values);
12521             return '';
12522         }
12523         try {
12524             return t.compiled.call(this, vs, parent);
12525         } catch (e) {
12526             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12527             Roo.log(e.body);
12528             //Roo.log(t.compiled);
12529             Roo.log(values);
12530             return '';
12531         }
12532     },
12533
12534    
12535
12536     applyTemplate : function(values){
12537         return this.master.compiled.call(this, values, {});
12538         //var s = this.subs;
12539     },
12540
12541     apply : function(){
12542         return this.applyTemplate.apply(this, arguments);
12543     }
12544
12545  });
12546
12547 Roo.DomTemplate.from = function(el){
12548     el = Roo.getDom(el);
12549     return new Roo.Domtemplate(el.value || el.innerHTML);
12550 };/*
12551  * Based on:
12552  * Ext JS Library 1.1.1
12553  * Copyright(c) 2006-2007, Ext JS, LLC.
12554  *
12555  * Originally Released Under LGPL - original licence link has changed is not relivant.
12556  *
12557  * Fork - LGPL
12558  * <script type="text/javascript">
12559  */
12560
12561 /**
12562  * @class Roo.util.DelayedTask
12563  * Provides a convenient method of performing setTimeout where a new
12564  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12565  * You can use this class to buffer
12566  * the keypress events for a certain number of milliseconds, and perform only if they stop
12567  * for that amount of time.
12568  * @constructor The parameters to this constructor serve as defaults and are not required.
12569  * @param {Function} fn (optional) The default function to timeout
12570  * @param {Object} scope (optional) The default scope of that timeout
12571  * @param {Array} args (optional) The default Array of arguments
12572  */
12573 Roo.util.DelayedTask = function(fn, scope, args){
12574     var id = null, d, t;
12575
12576     var call = function(){
12577         var now = new Date().getTime();
12578         if(now - t >= d){
12579             clearInterval(id);
12580             id = null;
12581             fn.apply(scope, args || []);
12582         }
12583     };
12584     /**
12585      * Cancels any pending timeout and queues a new one
12586      * @param {Number} delay The milliseconds to delay
12587      * @param {Function} newFn (optional) Overrides function passed to constructor
12588      * @param {Object} newScope (optional) Overrides scope passed to constructor
12589      * @param {Array} newArgs (optional) Overrides args passed to constructor
12590      */
12591     this.delay = function(delay, newFn, newScope, newArgs){
12592         if(id && delay != d){
12593             this.cancel();
12594         }
12595         d = delay;
12596         t = new Date().getTime();
12597         fn = newFn || fn;
12598         scope = newScope || scope;
12599         args = newArgs || args;
12600         if(!id){
12601             id = setInterval(call, d);
12602         }
12603     };
12604
12605     /**
12606      * Cancel the last queued timeout
12607      */
12608     this.cancel = function(){
12609         if(id){
12610             clearInterval(id);
12611             id = null;
12612         }
12613     };
12614 };/*
12615  * Based on:
12616  * Ext JS Library 1.1.1
12617  * Copyright(c) 2006-2007, Ext JS, LLC.
12618  *
12619  * Originally Released Under LGPL - original licence link has changed is not relivant.
12620  *
12621  * Fork - LGPL
12622  * <script type="text/javascript">
12623  */
12624  
12625  
12626 Roo.util.TaskRunner = function(interval){
12627     interval = interval || 10;
12628     var tasks = [], removeQueue = [];
12629     var id = 0;
12630     var running = false;
12631
12632     var stopThread = function(){
12633         running = false;
12634         clearInterval(id);
12635         id = 0;
12636     };
12637
12638     var startThread = function(){
12639         if(!running){
12640             running = true;
12641             id = setInterval(runTasks, interval);
12642         }
12643     };
12644
12645     var removeTask = function(task){
12646         removeQueue.push(task);
12647         if(task.onStop){
12648             task.onStop();
12649         }
12650     };
12651
12652     var runTasks = function(){
12653         if(removeQueue.length > 0){
12654             for(var i = 0, len = removeQueue.length; i < len; i++){
12655                 tasks.remove(removeQueue[i]);
12656             }
12657             removeQueue = [];
12658             if(tasks.length < 1){
12659                 stopThread();
12660                 return;
12661             }
12662         }
12663         var now = new Date().getTime();
12664         for(var i = 0, len = tasks.length; i < len; ++i){
12665             var t = tasks[i];
12666             var itime = now - t.taskRunTime;
12667             if(t.interval <= itime){
12668                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12669                 t.taskRunTime = now;
12670                 if(rt === false || t.taskRunCount === t.repeat){
12671                     removeTask(t);
12672                     return;
12673                 }
12674             }
12675             if(t.duration && t.duration <= (now - t.taskStartTime)){
12676                 removeTask(t);
12677             }
12678         }
12679     };
12680
12681     /**
12682      * Queues a new task.
12683      * @param {Object} task
12684      */
12685     this.start = function(task){
12686         tasks.push(task);
12687         task.taskStartTime = new Date().getTime();
12688         task.taskRunTime = 0;
12689         task.taskRunCount = 0;
12690         startThread();
12691         return task;
12692     };
12693
12694     this.stop = function(task){
12695         removeTask(task);
12696         return task;
12697     };
12698
12699     this.stopAll = function(){
12700         stopThread();
12701         for(var i = 0, len = tasks.length; i < len; i++){
12702             if(tasks[i].onStop){
12703                 tasks[i].onStop();
12704             }
12705         }
12706         tasks = [];
12707         removeQueue = [];
12708     };
12709 };
12710
12711 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12712  * Based on:
12713  * Ext JS Library 1.1.1
12714  * Copyright(c) 2006-2007, Ext JS, LLC.
12715  *
12716  * Originally Released Under LGPL - original licence link has changed is not relivant.
12717  *
12718  * Fork - LGPL
12719  * <script type="text/javascript">
12720  */
12721
12722  
12723 /**
12724  * @class Roo.util.MixedCollection
12725  * @extends Roo.util.Observable
12726  * A Collection class that maintains both numeric indexes and keys and exposes events.
12727  * @constructor
12728  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12729  * collection (defaults to false)
12730  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12731  * and return the key value for that item.  This is used when available to look up the key on items that
12732  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12733  * equivalent to providing an implementation for the {@link #getKey} method.
12734  */
12735 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12736     this.items = [];
12737     this.map = {};
12738     this.keys = [];
12739     this.length = 0;
12740     this.addEvents({
12741         /**
12742          * @event clear
12743          * Fires when the collection is cleared.
12744          */
12745         "clear" : true,
12746         /**
12747          * @event add
12748          * Fires when an item is added to the collection.
12749          * @param {Number} index The index at which the item was added.
12750          * @param {Object} o The item added.
12751          * @param {String} key The key associated with the added item.
12752          */
12753         "add" : true,
12754         /**
12755          * @event replace
12756          * Fires when an item is replaced in the collection.
12757          * @param {String} key he key associated with the new added.
12758          * @param {Object} old The item being replaced.
12759          * @param {Object} new The new item.
12760          */
12761         "replace" : true,
12762         /**
12763          * @event remove
12764          * Fires when an item is removed from the collection.
12765          * @param {Object} o The item being removed.
12766          * @param {String} key (optional) The key associated with the removed item.
12767          */
12768         "remove" : true,
12769         "sort" : true
12770     });
12771     this.allowFunctions = allowFunctions === true;
12772     if(keyFn){
12773         this.getKey = keyFn;
12774     }
12775     Roo.util.MixedCollection.superclass.constructor.call(this);
12776 };
12777
12778 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12779     allowFunctions : false,
12780     
12781 /**
12782  * Adds an item to the collection.
12783  * @param {String} key The key to associate with the item
12784  * @param {Object} o The item to add.
12785  * @return {Object} The item added.
12786  */
12787     add : function(key, o){
12788         if(arguments.length == 1){
12789             o = arguments[0];
12790             key = this.getKey(o);
12791         }
12792         if(typeof key == "undefined" || key === null){
12793             this.length++;
12794             this.items.push(o);
12795             this.keys.push(null);
12796         }else{
12797             var old = this.map[key];
12798             if(old){
12799                 return this.replace(key, o);
12800             }
12801             this.length++;
12802             this.items.push(o);
12803             this.map[key] = o;
12804             this.keys.push(key);
12805         }
12806         this.fireEvent("add", this.length-1, o, key);
12807         return o;
12808     },
12809        
12810 /**
12811   * MixedCollection has a generic way to fetch keys if you implement getKey.
12812 <pre><code>
12813 // normal way
12814 var mc = new Roo.util.MixedCollection();
12815 mc.add(someEl.dom.id, someEl);
12816 mc.add(otherEl.dom.id, otherEl);
12817 //and so on
12818
12819 // using getKey
12820 var mc = new Roo.util.MixedCollection();
12821 mc.getKey = function(el){
12822    return el.dom.id;
12823 };
12824 mc.add(someEl);
12825 mc.add(otherEl);
12826
12827 // or via the constructor
12828 var mc = new Roo.util.MixedCollection(false, function(el){
12829    return el.dom.id;
12830 });
12831 mc.add(someEl);
12832 mc.add(otherEl);
12833 </code></pre>
12834  * @param o {Object} The item for which to find the key.
12835  * @return {Object} The key for the passed item.
12836  */
12837     getKey : function(o){
12838          return o.id; 
12839     },
12840    
12841 /**
12842  * Replaces an item in the collection.
12843  * @param {String} key The key associated with the item to replace, or the item to replace.
12844  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12845  * @return {Object}  The new item.
12846  */
12847     replace : function(key, o){
12848         if(arguments.length == 1){
12849             o = arguments[0];
12850             key = this.getKey(o);
12851         }
12852         var old = this.item(key);
12853         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12854              return this.add(key, o);
12855         }
12856         var index = this.indexOfKey(key);
12857         this.items[index] = o;
12858         this.map[key] = o;
12859         this.fireEvent("replace", key, old, o);
12860         return o;
12861     },
12862    
12863 /**
12864  * Adds all elements of an Array or an Object to the collection.
12865  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12866  * an Array of values, each of which are added to the collection.
12867  */
12868     addAll : function(objs){
12869         if(arguments.length > 1 || objs instanceof Array){
12870             var args = arguments.length > 1 ? arguments : objs;
12871             for(var i = 0, len = args.length; i < len; i++){
12872                 this.add(args[i]);
12873             }
12874         }else{
12875             for(var key in objs){
12876                 if(this.allowFunctions || typeof objs[key] != "function"){
12877                     this.add(key, objs[key]);
12878                 }
12879             }
12880         }
12881     },
12882    
12883 /**
12884  * Executes the specified function once for every item in the collection, passing each
12885  * item as the first and only parameter. returning false from the function will stop the iteration.
12886  * @param {Function} fn The function to execute for each item.
12887  * @param {Object} scope (optional) The scope in which to execute the function.
12888  */
12889     each : function(fn, scope){
12890         var items = [].concat(this.items); // each safe for removal
12891         for(var i = 0, len = items.length; i < len; i++){
12892             if(fn.call(scope || items[i], items[i], i, len) === false){
12893                 break;
12894             }
12895         }
12896     },
12897    
12898 /**
12899  * Executes the specified function once for every key in the collection, passing each
12900  * key, and its associated item as the first two parameters.
12901  * @param {Function} fn The function to execute for each item.
12902  * @param {Object} scope (optional) The scope in which to execute the function.
12903  */
12904     eachKey : function(fn, scope){
12905         for(var i = 0, len = this.keys.length; i < len; i++){
12906             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12907         }
12908     },
12909    
12910 /**
12911  * Returns the first item in the collection which elicits a true return value from the
12912  * passed selection function.
12913  * @param {Function} fn The selection function to execute for each item.
12914  * @param {Object} scope (optional) The scope in which to execute the function.
12915  * @return {Object} The first item in the collection which returned true from the selection function.
12916  */
12917     find : function(fn, scope){
12918         for(var i = 0, len = this.items.length; i < len; i++){
12919             if(fn.call(scope || window, this.items[i], this.keys[i])){
12920                 return this.items[i];
12921             }
12922         }
12923         return null;
12924     },
12925    
12926 /**
12927  * Inserts an item at the specified index in the collection.
12928  * @param {Number} index The index to insert the item at.
12929  * @param {String} key The key to associate with the new item, or the item itself.
12930  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12931  * @return {Object} The item inserted.
12932  */
12933     insert : function(index, key, o){
12934         if(arguments.length == 2){
12935             o = arguments[1];
12936             key = this.getKey(o);
12937         }
12938         if(index >= this.length){
12939             return this.add(key, o);
12940         }
12941         this.length++;
12942         this.items.splice(index, 0, o);
12943         if(typeof key != "undefined" && key != null){
12944             this.map[key] = o;
12945         }
12946         this.keys.splice(index, 0, key);
12947         this.fireEvent("add", index, o, key);
12948         return o;
12949     },
12950    
12951 /**
12952  * Removed an item from the collection.
12953  * @param {Object} o The item to remove.
12954  * @return {Object} The item removed.
12955  */
12956     remove : function(o){
12957         return this.removeAt(this.indexOf(o));
12958     },
12959    
12960 /**
12961  * Remove an item from a specified index in the collection.
12962  * @param {Number} index The index within the collection of the item to remove.
12963  */
12964     removeAt : function(index){
12965         if(index < this.length && index >= 0){
12966             this.length--;
12967             var o = this.items[index];
12968             this.items.splice(index, 1);
12969             var key = this.keys[index];
12970             if(typeof key != "undefined"){
12971                 delete this.map[key];
12972             }
12973             this.keys.splice(index, 1);
12974             this.fireEvent("remove", o, key);
12975         }
12976     },
12977    
12978 /**
12979  * Removed an item associated with the passed key fom the collection.
12980  * @param {String} key The key of the item to remove.
12981  */
12982     removeKey : function(key){
12983         return this.removeAt(this.indexOfKey(key));
12984     },
12985    
12986 /**
12987  * Returns the number of items in the collection.
12988  * @return {Number} the number of items in the collection.
12989  */
12990     getCount : function(){
12991         return this.length; 
12992     },
12993    
12994 /**
12995  * Returns index within the collection of the passed Object.
12996  * @param {Object} o The item to find the index of.
12997  * @return {Number} index of the item.
12998  */
12999     indexOf : function(o){
13000         if(!this.items.indexOf){
13001             for(var i = 0, len = this.items.length; i < len; i++){
13002                 if(this.items[i] == o) return i;
13003             }
13004             return -1;
13005         }else{
13006             return this.items.indexOf(o);
13007         }
13008     },
13009    
13010 /**
13011  * Returns index within the collection of the passed key.
13012  * @param {String} key The key to find the index of.
13013  * @return {Number} index of the key.
13014  */
13015     indexOfKey : function(key){
13016         if(!this.keys.indexOf){
13017             for(var i = 0, len = this.keys.length; i < len; i++){
13018                 if(this.keys[i] == key) return i;
13019             }
13020             return -1;
13021         }else{
13022             return this.keys.indexOf(key);
13023         }
13024     },
13025    
13026 /**
13027  * Returns the item associated with the passed key OR index. Key has priority over index.
13028  * @param {String/Number} key The key or index of the item.
13029  * @return {Object} The item associated with the passed key.
13030  */
13031     item : function(key){
13032         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13033         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13034     },
13035     
13036 /**
13037  * Returns the item at the specified index.
13038  * @param {Number} index The index of the item.
13039  * @return {Object}
13040  */
13041     itemAt : function(index){
13042         return this.items[index];
13043     },
13044     
13045 /**
13046  * Returns the item associated with the passed key.
13047  * @param {String/Number} key The key of the item.
13048  * @return {Object} The item associated with the passed key.
13049  */
13050     key : function(key){
13051         return this.map[key];
13052     },
13053    
13054 /**
13055  * Returns true if the collection contains the passed Object as an item.
13056  * @param {Object} o  The Object to look for in the collection.
13057  * @return {Boolean} True if the collection contains the Object as an item.
13058  */
13059     contains : function(o){
13060         return this.indexOf(o) != -1;
13061     },
13062    
13063 /**
13064  * Returns true if the collection contains the passed Object as a key.
13065  * @param {String} key The key to look for in the collection.
13066  * @return {Boolean} True if the collection contains the Object as a key.
13067  */
13068     containsKey : function(key){
13069         return typeof this.map[key] != "undefined";
13070     },
13071    
13072 /**
13073  * Removes all items from the collection.
13074  */
13075     clear : function(){
13076         this.length = 0;
13077         this.items = [];
13078         this.keys = [];
13079         this.map = {};
13080         this.fireEvent("clear");
13081     },
13082    
13083 /**
13084  * Returns the first item in the collection.
13085  * @return {Object} the first item in the collection..
13086  */
13087     first : function(){
13088         return this.items[0]; 
13089     },
13090    
13091 /**
13092  * Returns the last item in the collection.
13093  * @return {Object} the last item in the collection..
13094  */
13095     last : function(){
13096         return this.items[this.length-1];   
13097     },
13098     
13099     _sort : function(property, dir, fn){
13100         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13101         fn = fn || function(a, b){
13102             return a-b;
13103         };
13104         var c = [], k = this.keys, items = this.items;
13105         for(var i = 0, len = items.length; i < len; i++){
13106             c[c.length] = {key: k[i], value: items[i], index: i};
13107         }
13108         c.sort(function(a, b){
13109             var v = fn(a[property], b[property]) * dsc;
13110             if(v == 0){
13111                 v = (a.index < b.index ? -1 : 1);
13112             }
13113             return v;
13114         });
13115         for(var i = 0, len = c.length; i < len; i++){
13116             items[i] = c[i].value;
13117             k[i] = c[i].key;
13118         }
13119         this.fireEvent("sort", this);
13120     },
13121     
13122     /**
13123      * Sorts this collection with the passed comparison function
13124      * @param {String} direction (optional) "ASC" or "DESC"
13125      * @param {Function} fn (optional) comparison function
13126      */
13127     sort : function(dir, fn){
13128         this._sort("value", dir, fn);
13129     },
13130     
13131     /**
13132      * Sorts this collection by keys
13133      * @param {String} direction (optional) "ASC" or "DESC"
13134      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13135      */
13136     keySort : function(dir, fn){
13137         this._sort("key", dir, fn || function(a, b){
13138             return String(a).toUpperCase()-String(b).toUpperCase();
13139         });
13140     },
13141     
13142     /**
13143      * Returns a range of items in this collection
13144      * @param {Number} startIndex (optional) defaults to 0
13145      * @param {Number} endIndex (optional) default to the last item
13146      * @return {Array} An array of items
13147      */
13148     getRange : function(start, end){
13149         var items = this.items;
13150         if(items.length < 1){
13151             return [];
13152         }
13153         start = start || 0;
13154         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13155         var r = [];
13156         if(start <= end){
13157             for(var i = start; i <= end; i++) {
13158                     r[r.length] = items[i];
13159             }
13160         }else{
13161             for(var i = start; i >= end; i--) {
13162                     r[r.length] = items[i];
13163             }
13164         }
13165         return r;
13166     },
13167         
13168     /**
13169      * Filter the <i>objects</i> in this collection by a specific property. 
13170      * Returns a new collection that has been filtered.
13171      * @param {String} property A property on your objects
13172      * @param {String/RegExp} value Either string that the property values 
13173      * should start with or a RegExp to test against the property
13174      * @return {MixedCollection} The new filtered collection
13175      */
13176     filter : function(property, value){
13177         if(!value.exec){ // not a regex
13178             value = String(value);
13179             if(value.length == 0){
13180                 return this.clone();
13181             }
13182             value = new RegExp("^" + Roo.escapeRe(value), "i");
13183         }
13184         return this.filterBy(function(o){
13185             return o && value.test(o[property]);
13186         });
13187         },
13188     
13189     /**
13190      * Filter by a function. * Returns a new collection that has been filtered.
13191      * The passed function will be called with each 
13192      * object in the collection. If the function returns true, the value is included 
13193      * otherwise it is filtered.
13194      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13195      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13196      * @return {MixedCollection} The new filtered collection
13197      */
13198     filterBy : function(fn, scope){
13199         var r = new Roo.util.MixedCollection();
13200         r.getKey = this.getKey;
13201         var k = this.keys, it = this.items;
13202         for(var i = 0, len = it.length; i < len; i++){
13203             if(fn.call(scope||this, it[i], k[i])){
13204                                 r.add(k[i], it[i]);
13205                         }
13206         }
13207         return r;
13208     },
13209     
13210     /**
13211      * Creates a duplicate of this collection
13212      * @return {MixedCollection}
13213      */
13214     clone : function(){
13215         var r = new Roo.util.MixedCollection();
13216         var k = this.keys, it = this.items;
13217         for(var i = 0, len = it.length; i < len; i++){
13218             r.add(k[i], it[i]);
13219         }
13220         r.getKey = this.getKey;
13221         return r;
13222     }
13223 });
13224 /**
13225  * Returns the item associated with the passed key or index.
13226  * @method
13227  * @param {String/Number} key The key or index of the item.
13228  * @return {Object} The item associated with the passed key.
13229  */
13230 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13231  * Based on:
13232  * Ext JS Library 1.1.1
13233  * Copyright(c) 2006-2007, Ext JS, LLC.
13234  *
13235  * Originally Released Under LGPL - original licence link has changed is not relivant.
13236  *
13237  * Fork - LGPL
13238  * <script type="text/javascript">
13239  */
13240 /**
13241  * @class Roo.util.JSON
13242  * Modified version of Douglas Crockford"s json.js that doesn"t
13243  * mess with the Object prototype 
13244  * http://www.json.org/js.html
13245  * @singleton
13246  */
13247 Roo.util.JSON = new (function(){
13248     var useHasOwn = {}.hasOwnProperty ? true : false;
13249     
13250     // crashes Safari in some instances
13251     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13252     
13253     var pad = function(n) {
13254         return n < 10 ? "0" + n : n;
13255     };
13256     
13257     var m = {
13258         "\b": '\\b',
13259         "\t": '\\t',
13260         "\n": '\\n',
13261         "\f": '\\f',
13262         "\r": '\\r',
13263         '"' : '\\"',
13264         "\\": '\\\\'
13265     };
13266
13267     var encodeString = function(s){
13268         if (/["\\\x00-\x1f]/.test(s)) {
13269             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13270                 var c = m[b];
13271                 if(c){
13272                     return c;
13273                 }
13274                 c = b.charCodeAt();
13275                 return "\\u00" +
13276                     Math.floor(c / 16).toString(16) +
13277                     (c % 16).toString(16);
13278             }) + '"';
13279         }
13280         return '"' + s + '"';
13281     };
13282     
13283     var encodeArray = function(o){
13284         var a = ["["], b, i, l = o.length, v;
13285             for (i = 0; i < l; i += 1) {
13286                 v = o[i];
13287                 switch (typeof v) {
13288                     case "undefined":
13289                     case "function":
13290                     case "unknown":
13291                         break;
13292                     default:
13293                         if (b) {
13294                             a.push(',');
13295                         }
13296                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13297                         b = true;
13298                 }
13299             }
13300             a.push("]");
13301             return a.join("");
13302     };
13303     
13304     var encodeDate = function(o){
13305         return '"' + o.getFullYear() + "-" +
13306                 pad(o.getMonth() + 1) + "-" +
13307                 pad(o.getDate()) + "T" +
13308                 pad(o.getHours()) + ":" +
13309                 pad(o.getMinutes()) + ":" +
13310                 pad(o.getSeconds()) + '"';
13311     };
13312     
13313     /**
13314      * Encodes an Object, Array or other value
13315      * @param {Mixed} o The variable to encode
13316      * @return {String} The JSON string
13317      */
13318     this.encode = function(o)
13319     {
13320         // should this be extended to fully wrap stringify..
13321         
13322         if(typeof o == "undefined" || o === null){
13323             return "null";
13324         }else if(o instanceof Array){
13325             return encodeArray(o);
13326         }else if(o instanceof Date){
13327             return encodeDate(o);
13328         }else if(typeof o == "string"){
13329             return encodeString(o);
13330         }else if(typeof o == "number"){
13331             return isFinite(o) ? String(o) : "null";
13332         }else if(typeof o == "boolean"){
13333             return String(o);
13334         }else {
13335             var a = ["{"], b, i, v;
13336             for (i in o) {
13337                 if(!useHasOwn || o.hasOwnProperty(i)) {
13338                     v = o[i];
13339                     switch (typeof v) {
13340                     case "undefined":
13341                     case "function":
13342                     case "unknown":
13343                         break;
13344                     default:
13345                         if(b){
13346                             a.push(',');
13347                         }
13348                         a.push(this.encode(i), ":",
13349                                 v === null ? "null" : this.encode(v));
13350                         b = true;
13351                     }
13352                 }
13353             }
13354             a.push("}");
13355             return a.join("");
13356         }
13357     };
13358     
13359     /**
13360      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13361      * @param {String} json The JSON string
13362      * @return {Object} The resulting object
13363      */
13364     this.decode = function(json){
13365         
13366         return  /** eval:var:json */ eval("(" + json + ')');
13367     };
13368 })();
13369 /** 
13370  * Shorthand for {@link Roo.util.JSON#encode}
13371  * @member Roo encode 
13372  * @method */
13373 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13374 /** 
13375  * Shorthand for {@link Roo.util.JSON#decode}
13376  * @member Roo decode 
13377  * @method */
13378 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13379 /*
13380  * Based on:
13381  * Ext JS Library 1.1.1
13382  * Copyright(c) 2006-2007, Ext JS, LLC.
13383  *
13384  * Originally Released Under LGPL - original licence link has changed is not relivant.
13385  *
13386  * Fork - LGPL
13387  * <script type="text/javascript">
13388  */
13389  
13390 /**
13391  * @class Roo.util.Format
13392  * Reusable data formatting functions
13393  * @singleton
13394  */
13395 Roo.util.Format = function(){
13396     var trimRe = /^\s+|\s+$/g;
13397     return {
13398         /**
13399          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13400          * @param {String} value The string to truncate
13401          * @param {Number} length The maximum length to allow before truncating
13402          * @return {String} The converted text
13403          */
13404         ellipsis : function(value, len){
13405             if(value && value.length > len){
13406                 return value.substr(0, len-3)+"...";
13407             }
13408             return value;
13409         },
13410
13411         /**
13412          * Checks a reference and converts it to empty string if it is undefined
13413          * @param {Mixed} value Reference to check
13414          * @return {Mixed} Empty string if converted, otherwise the original value
13415          */
13416         undef : function(value){
13417             return typeof value != "undefined" ? value : "";
13418         },
13419
13420         /**
13421          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13422          * @param {String} value The string to encode
13423          * @return {String} The encoded text
13424          */
13425         htmlEncode : function(value){
13426             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13427         },
13428
13429         /**
13430          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13431          * @param {String} value The string to decode
13432          * @return {String} The decoded text
13433          */
13434         htmlDecode : function(value){
13435             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13436         },
13437
13438         /**
13439          * Trims any whitespace from either side of a string
13440          * @param {String} value The text to trim
13441          * @return {String} The trimmed text
13442          */
13443         trim : function(value){
13444             return String(value).replace(trimRe, "");
13445         },
13446
13447         /**
13448          * Returns a substring from within an original string
13449          * @param {String} value The original text
13450          * @param {Number} start The start index of the substring
13451          * @param {Number} length The length of the substring
13452          * @return {String} The substring
13453          */
13454         substr : function(value, start, length){
13455             return String(value).substr(start, length);
13456         },
13457
13458         /**
13459          * Converts a string to all lower case letters
13460          * @param {String} value The text to convert
13461          * @return {String} The converted text
13462          */
13463         lowercase : function(value){
13464             return String(value).toLowerCase();
13465         },
13466
13467         /**
13468          * Converts a string to all upper case letters
13469          * @param {String} value The text to convert
13470          * @return {String} The converted text
13471          */
13472         uppercase : function(value){
13473             return String(value).toUpperCase();
13474         },
13475
13476         /**
13477          * Converts the first character only of a string to upper case
13478          * @param {String} value The text to convert
13479          * @return {String} The converted text
13480          */
13481         capitalize : function(value){
13482             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13483         },
13484
13485         // private
13486         call : function(value, fn){
13487             if(arguments.length > 2){
13488                 var args = Array.prototype.slice.call(arguments, 2);
13489                 args.unshift(value);
13490                  
13491                 return /** eval:var:value */  eval(fn).apply(window, args);
13492             }else{
13493                 /** eval:var:value */
13494                 return /** eval:var:value */ eval(fn).call(window, value);
13495             }
13496         },
13497
13498        
13499         /**
13500          * safer version of Math.toFixed..??/
13501          * @param {Number/String} value The numeric value to format
13502          * @param {Number/String} value Decimal places 
13503          * @return {String} The formatted currency string
13504          */
13505         toFixed : function(v, n)
13506         {
13507             // why not use to fixed - precision is buggered???
13508             if (!n) {
13509                 return Math.round(v-0);
13510             }
13511             var fact = Math.pow(10,n+1);
13512             v = (Math.round((v-0)*fact))/fact;
13513             var z = (''+fact).substring(2);
13514             if (v == Math.floor(v)) {
13515                 return Math.floor(v) + '.' + z;
13516             }
13517             
13518             // now just padd decimals..
13519             var ps = String(v).split('.');
13520             var fd = (ps[1] + z);
13521             var r = fd.substring(0,n); 
13522             var rm = fd.substring(n); 
13523             if (rm < 5) {
13524                 return ps[0] + '.' + r;
13525             }
13526             r*=1; // turn it into a number;
13527             r++;
13528             if (String(r).length != n) {
13529                 ps[0]*=1;
13530                 ps[0]++;
13531                 r = String(r).substring(1); // chop the end off.
13532             }
13533             
13534             return ps[0] + '.' + r;
13535              
13536         },
13537         
13538         /**
13539          * Format a number as US currency
13540          * @param {Number/String} value The numeric value to format
13541          * @return {String} The formatted currency string
13542          */
13543         usMoney : function(v){
13544             return '$' + Roo.util.Format.number(v);
13545         },
13546         
13547         /**
13548          * Format a number
13549          * eventually this should probably emulate php's number_format
13550          * @param {Number/String} value The numeric value to format
13551          * @param {Number} decimals number of decimal places
13552          * @return {String} The formatted currency string
13553          */
13554         number : function(v,decimals)
13555         {
13556             // multiply and round.
13557             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13558             var mul = Math.pow(10, decimals);
13559             var zero = String(mul).substring(1);
13560             v = (Math.round((v-0)*mul))/mul;
13561             
13562             // if it's '0' number.. then
13563             
13564             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13565             v = String(v);
13566             var ps = v.split('.');
13567             var whole = ps[0];
13568             
13569             
13570             var r = /(\d+)(\d{3})/;
13571             // add comma's
13572             while (r.test(whole)) {
13573                 whole = whole.replace(r, '$1' + ',' + '$2');
13574             }
13575             
13576             
13577             var sub = ps[1] ?
13578                     // has decimals..
13579                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13580                     // does not have decimals
13581                     (decimals ? ('.' + zero) : '');
13582             
13583             
13584             return whole + sub ;
13585         },
13586         
13587         /**
13588          * Parse a value into a formatted date using the specified format pattern.
13589          * @param {Mixed} value The value to format
13590          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13591          * @return {String} The formatted date string
13592          */
13593         date : function(v, format){
13594             if(!v){
13595                 return "";
13596             }
13597             if(!(v instanceof Date)){
13598                 v = new Date(Date.parse(v));
13599             }
13600             return v.dateFormat(format || "m/d/Y");
13601         },
13602
13603         /**
13604          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13605          * @param {String} format Any valid date format string
13606          * @return {Function} The date formatting function
13607          */
13608         dateRenderer : function(format){
13609             return function(v){
13610                 return Roo.util.Format.date(v, format);  
13611             };
13612         },
13613
13614         // private
13615         stripTagsRE : /<\/?[^>]+>/gi,
13616         
13617         /**
13618          * Strips all HTML tags
13619          * @param {Mixed} value The text from which to strip tags
13620          * @return {String} The stripped text
13621          */
13622         stripTags : function(v){
13623             return !v ? v : String(v).replace(this.stripTagsRE, "");
13624         }
13625     };
13626 }();/*
13627  * Based on:
13628  * Ext JS Library 1.1.1
13629  * Copyright(c) 2006-2007, Ext JS, LLC.
13630  *
13631  * Originally Released Under LGPL - original licence link has changed is not relivant.
13632  *
13633  * Fork - LGPL
13634  * <script type="text/javascript">
13635  */
13636
13637
13638  
13639
13640 /**
13641  * @class Roo.MasterTemplate
13642  * @extends Roo.Template
13643  * Provides a template that can have child templates. The syntax is:
13644 <pre><code>
13645 var t = new Roo.MasterTemplate(
13646         '&lt;select name="{name}"&gt;',
13647                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13648         '&lt;/select&gt;'
13649 );
13650 t.add('options', {value: 'foo', text: 'bar'});
13651 // or you can add multiple child elements in one shot
13652 t.addAll('options', [
13653     {value: 'foo', text: 'bar'},
13654     {value: 'foo2', text: 'bar2'},
13655     {value: 'foo3', text: 'bar3'}
13656 ]);
13657 // then append, applying the master template values
13658 t.append('my-form', {name: 'my-select'});
13659 </code></pre>
13660 * A name attribute for the child template is not required if you have only one child
13661 * template or you want to refer to them by index.
13662  */
13663 Roo.MasterTemplate = function(){
13664     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13665     this.originalHtml = this.html;
13666     var st = {};
13667     var m, re = this.subTemplateRe;
13668     re.lastIndex = 0;
13669     var subIndex = 0;
13670     while(m = re.exec(this.html)){
13671         var name = m[1], content = m[2];
13672         st[subIndex] = {
13673             name: name,
13674             index: subIndex,
13675             buffer: [],
13676             tpl : new Roo.Template(content)
13677         };
13678         if(name){
13679             st[name] = st[subIndex];
13680         }
13681         st[subIndex].tpl.compile();
13682         st[subIndex].tpl.call = this.call.createDelegate(this);
13683         subIndex++;
13684     }
13685     this.subCount = subIndex;
13686     this.subs = st;
13687 };
13688 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13689     /**
13690     * The regular expression used to match sub templates
13691     * @type RegExp
13692     * @property
13693     */
13694     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13695
13696     /**
13697      * Applies the passed values to a child template.
13698      * @param {String/Number} name (optional) The name or index of the child template
13699      * @param {Array/Object} values The values to be applied to the template
13700      * @return {MasterTemplate} this
13701      */
13702      add : function(name, values){
13703         if(arguments.length == 1){
13704             values = arguments[0];
13705             name = 0;
13706         }
13707         var s = this.subs[name];
13708         s.buffer[s.buffer.length] = s.tpl.apply(values);
13709         return this;
13710     },
13711
13712     /**
13713      * Applies all the passed values to a child template.
13714      * @param {String/Number} name (optional) The name or index of the child template
13715      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13716      * @param {Boolean} reset (optional) True to reset the template first
13717      * @return {MasterTemplate} this
13718      */
13719     fill : function(name, values, reset){
13720         var a = arguments;
13721         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13722             values = a[0];
13723             name = 0;
13724             reset = a[1];
13725         }
13726         if(reset){
13727             this.reset();
13728         }
13729         for(var i = 0, len = values.length; i < len; i++){
13730             this.add(name, values[i]);
13731         }
13732         return this;
13733     },
13734
13735     /**
13736      * Resets the template for reuse
13737      * @return {MasterTemplate} this
13738      */
13739      reset : function(){
13740         var s = this.subs;
13741         for(var i = 0; i < this.subCount; i++){
13742             s[i].buffer = [];
13743         }
13744         return this;
13745     },
13746
13747     applyTemplate : function(values){
13748         var s = this.subs;
13749         var replaceIndex = -1;
13750         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13751             return s[++replaceIndex].buffer.join("");
13752         });
13753         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13754     },
13755
13756     apply : function(){
13757         return this.applyTemplate.apply(this, arguments);
13758     },
13759
13760     compile : function(){return this;}
13761 });
13762
13763 /**
13764  * Alias for fill().
13765  * @method
13766  */
13767 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13768  /**
13769  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13770  * var tpl = Roo.MasterTemplate.from('element-id');
13771  * @param {String/HTMLElement} el
13772  * @param {Object} config
13773  * @static
13774  */
13775 Roo.MasterTemplate.from = function(el, config){
13776     el = Roo.getDom(el);
13777     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13778 };/*
13779  * Based on:
13780  * Ext JS Library 1.1.1
13781  * Copyright(c) 2006-2007, Ext JS, LLC.
13782  *
13783  * Originally Released Under LGPL - original licence link has changed is not relivant.
13784  *
13785  * Fork - LGPL
13786  * <script type="text/javascript">
13787  */
13788
13789  
13790 /**
13791  * @class Roo.util.CSS
13792  * Utility class for manipulating CSS rules
13793  * @singleton
13794  */
13795 Roo.util.CSS = function(){
13796         var rules = null;
13797         var doc = document;
13798
13799     var camelRe = /(-[a-z])/gi;
13800     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13801
13802    return {
13803    /**
13804     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13805     * tag and appended to the HEAD of the document.
13806     * @param {String|Object} cssText The text containing the css rules
13807     * @param {String} id An id to add to the stylesheet for later removal
13808     * @return {StyleSheet}
13809     */
13810     createStyleSheet : function(cssText, id){
13811         var ss;
13812         var head = doc.getElementsByTagName("head")[0];
13813         var nrules = doc.createElement("style");
13814         nrules.setAttribute("type", "text/css");
13815         if(id){
13816             nrules.setAttribute("id", id);
13817         }
13818         if (typeof(cssText) != 'string') {
13819             // support object maps..
13820             // not sure if this a good idea.. 
13821             // perhaps it should be merged with the general css handling
13822             // and handle js style props.
13823             var cssTextNew = [];
13824             for(var n in cssText) {
13825                 var citems = [];
13826                 for(var k in cssText[n]) {
13827                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13828                 }
13829                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13830                 
13831             }
13832             cssText = cssTextNew.join("\n");
13833             
13834         }
13835        
13836        
13837        if(Roo.isIE){
13838            head.appendChild(nrules);
13839            ss = nrules.styleSheet;
13840            ss.cssText = cssText;
13841        }else{
13842            try{
13843                 nrules.appendChild(doc.createTextNode(cssText));
13844            }catch(e){
13845                nrules.cssText = cssText; 
13846            }
13847            head.appendChild(nrules);
13848            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13849        }
13850        this.cacheStyleSheet(ss);
13851        return ss;
13852    },
13853
13854    /**
13855     * Removes a style or link tag by id
13856     * @param {String} id The id of the tag
13857     */
13858    removeStyleSheet : function(id){
13859        var existing = doc.getElementById(id);
13860        if(existing){
13861            existing.parentNode.removeChild(existing);
13862        }
13863    },
13864
13865    /**
13866     * Dynamically swaps an existing stylesheet reference for a new one
13867     * @param {String} id The id of an existing link tag to remove
13868     * @param {String} url The href of the new stylesheet to include
13869     */
13870    swapStyleSheet : function(id, url){
13871        this.removeStyleSheet(id);
13872        var ss = doc.createElement("link");
13873        ss.setAttribute("rel", "stylesheet");
13874        ss.setAttribute("type", "text/css");
13875        ss.setAttribute("id", id);
13876        ss.setAttribute("href", url);
13877        doc.getElementsByTagName("head")[0].appendChild(ss);
13878    },
13879    
13880    /**
13881     * Refresh the rule cache if you have dynamically added stylesheets
13882     * @return {Object} An object (hash) of rules indexed by selector
13883     */
13884    refreshCache : function(){
13885        return this.getRules(true);
13886    },
13887
13888    // private
13889    cacheStyleSheet : function(stylesheet){
13890        if(!rules){
13891            rules = {};
13892        }
13893        try{// try catch for cross domain access issue
13894            var ssRules = stylesheet.cssRules || stylesheet.rules;
13895            for(var j = ssRules.length-1; j >= 0; --j){
13896                rules[ssRules[j].selectorText] = ssRules[j];
13897            }
13898        }catch(e){}
13899    },
13900    
13901    /**
13902     * Gets all css rules for the document
13903     * @param {Boolean} refreshCache true to refresh the internal cache
13904     * @return {Object} An object (hash) of rules indexed by selector
13905     */
13906    getRules : function(refreshCache){
13907                 if(rules == null || refreshCache){
13908                         rules = {};
13909                         var ds = doc.styleSheets;
13910                         for(var i =0, len = ds.length; i < len; i++){
13911                             try{
13912                         this.cacheStyleSheet(ds[i]);
13913                     }catch(e){} 
13914                 }
13915                 }
13916                 return rules;
13917         },
13918         
13919         /**
13920     * Gets an an individual CSS rule by selector(s)
13921     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13922     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13923     * @return {CSSRule} The CSS rule or null if one is not found
13924     */
13925    getRule : function(selector, refreshCache){
13926                 var rs = this.getRules(refreshCache);
13927                 if(!(selector instanceof Array)){
13928                     return rs[selector];
13929                 }
13930                 for(var i = 0; i < selector.length; i++){
13931                         if(rs[selector[i]]){
13932                                 return rs[selector[i]];
13933                         }
13934                 }
13935                 return null;
13936         },
13937         
13938         
13939         /**
13940     * Updates a rule property
13941     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13942     * @param {String} property The css property
13943     * @param {String} value The new value for the property
13944     * @return {Boolean} true If a rule was found and updated
13945     */
13946    updateRule : function(selector, property, value){
13947                 if(!(selector instanceof Array)){
13948                         var rule = this.getRule(selector);
13949                         if(rule){
13950                                 rule.style[property.replace(camelRe, camelFn)] = value;
13951                                 return true;
13952                         }
13953                 }else{
13954                         for(var i = 0; i < selector.length; i++){
13955                                 if(this.updateRule(selector[i], property, value)){
13956                                         return true;
13957                                 }
13958                         }
13959                 }
13960                 return false;
13961         }
13962    };   
13963 }();/*
13964  * Based on:
13965  * Ext JS Library 1.1.1
13966  * Copyright(c) 2006-2007, Ext JS, LLC.
13967  *
13968  * Originally Released Under LGPL - original licence link has changed is not relivant.
13969  *
13970  * Fork - LGPL
13971  * <script type="text/javascript">
13972  */
13973
13974  
13975
13976 /**
13977  * @class Roo.util.ClickRepeater
13978  * @extends Roo.util.Observable
13979  * 
13980  * A wrapper class which can be applied to any element. Fires a "click" event while the
13981  * mouse is pressed. The interval between firings may be specified in the config but
13982  * defaults to 10 milliseconds.
13983  * 
13984  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13985  * 
13986  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13987  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13988  * Similar to an autorepeat key delay.
13989  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13990  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13991  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13992  *           "interval" and "delay" are ignored. "immediate" is honored.
13993  * @cfg {Boolean} preventDefault True to prevent the default click event
13994  * @cfg {Boolean} stopDefault True to stop the default click event
13995  * 
13996  * @history
13997  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13998  *     2007-02-02 jvs Renamed to ClickRepeater
13999  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14000  *
14001  *  @constructor
14002  * @param {String/HTMLElement/Element} el The element to listen on
14003  * @param {Object} config
14004  **/
14005 Roo.util.ClickRepeater = function(el, config)
14006 {
14007     this.el = Roo.get(el);
14008     this.el.unselectable();
14009
14010     Roo.apply(this, config);
14011
14012     this.addEvents({
14013     /**
14014      * @event mousedown
14015      * Fires when the mouse button is depressed.
14016      * @param {Roo.util.ClickRepeater} this
14017      */
14018         "mousedown" : true,
14019     /**
14020      * @event click
14021      * Fires on a specified interval during the time the element is pressed.
14022      * @param {Roo.util.ClickRepeater} this
14023      */
14024         "click" : true,
14025     /**
14026      * @event mouseup
14027      * Fires when the mouse key is released.
14028      * @param {Roo.util.ClickRepeater} this
14029      */
14030         "mouseup" : true
14031     });
14032
14033     this.el.on("mousedown", this.handleMouseDown, this);
14034     if(this.preventDefault || this.stopDefault){
14035         this.el.on("click", function(e){
14036             if(this.preventDefault){
14037                 e.preventDefault();
14038             }
14039             if(this.stopDefault){
14040                 e.stopEvent();
14041             }
14042         }, this);
14043     }
14044
14045     // allow inline handler
14046     if(this.handler){
14047         this.on("click", this.handler,  this.scope || this);
14048     }
14049
14050     Roo.util.ClickRepeater.superclass.constructor.call(this);
14051 };
14052
14053 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14054     interval : 20,
14055     delay: 250,
14056     preventDefault : true,
14057     stopDefault : false,
14058     timer : 0,
14059
14060     // private
14061     handleMouseDown : function(){
14062         clearTimeout(this.timer);
14063         this.el.blur();
14064         if(this.pressClass){
14065             this.el.addClass(this.pressClass);
14066         }
14067         this.mousedownTime = new Date();
14068
14069         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14070         this.el.on("mouseout", this.handleMouseOut, this);
14071
14072         this.fireEvent("mousedown", this);
14073         this.fireEvent("click", this);
14074         
14075         this.timer = this.click.defer(this.delay || this.interval, this);
14076     },
14077
14078     // private
14079     click : function(){
14080         this.fireEvent("click", this);
14081         this.timer = this.click.defer(this.getInterval(), this);
14082     },
14083
14084     // private
14085     getInterval: function(){
14086         if(!this.accelerate){
14087             return this.interval;
14088         }
14089         var pressTime = this.mousedownTime.getElapsed();
14090         if(pressTime < 500){
14091             return 400;
14092         }else if(pressTime < 1700){
14093             return 320;
14094         }else if(pressTime < 2600){
14095             return 250;
14096         }else if(pressTime < 3500){
14097             return 180;
14098         }else if(pressTime < 4400){
14099             return 140;
14100         }else if(pressTime < 5300){
14101             return 80;
14102         }else if(pressTime < 6200){
14103             return 50;
14104         }else{
14105             return 10;
14106         }
14107     },
14108
14109     // private
14110     handleMouseOut : function(){
14111         clearTimeout(this.timer);
14112         if(this.pressClass){
14113             this.el.removeClass(this.pressClass);
14114         }
14115         this.el.on("mouseover", this.handleMouseReturn, this);
14116     },
14117
14118     // private
14119     handleMouseReturn : function(){
14120         this.el.un("mouseover", this.handleMouseReturn);
14121         if(this.pressClass){
14122             this.el.addClass(this.pressClass);
14123         }
14124         this.click();
14125     },
14126
14127     // private
14128     handleMouseUp : function(){
14129         clearTimeout(this.timer);
14130         this.el.un("mouseover", this.handleMouseReturn);
14131         this.el.un("mouseout", this.handleMouseOut);
14132         Roo.get(document).un("mouseup", this.handleMouseUp);
14133         this.el.removeClass(this.pressClass);
14134         this.fireEvent("mouseup", this);
14135     }
14136 });/*
14137  * Based on:
14138  * Ext JS Library 1.1.1
14139  * Copyright(c) 2006-2007, Ext JS, LLC.
14140  *
14141  * Originally Released Under LGPL - original licence link has changed is not relivant.
14142  *
14143  * Fork - LGPL
14144  * <script type="text/javascript">
14145  */
14146
14147  
14148 /**
14149  * @class Roo.KeyNav
14150  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14151  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14152  * way to implement custom navigation schemes for any UI component.</p>
14153  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14154  * pageUp, pageDown, del, home, end.  Usage:</p>
14155  <pre><code>
14156 var nav = new Roo.KeyNav("my-element", {
14157     "left" : function(e){
14158         this.moveLeft(e.ctrlKey);
14159     },
14160     "right" : function(e){
14161         this.moveRight(e.ctrlKey);
14162     },
14163     "enter" : function(e){
14164         this.save();
14165     },
14166     scope : this
14167 });
14168 </code></pre>
14169  * @constructor
14170  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14171  * @param {Object} config The config
14172  */
14173 Roo.KeyNav = function(el, config){
14174     this.el = Roo.get(el);
14175     Roo.apply(this, config);
14176     if(!this.disabled){
14177         this.disabled = true;
14178         this.enable();
14179     }
14180 };
14181
14182 Roo.KeyNav.prototype = {
14183     /**
14184      * @cfg {Boolean} disabled
14185      * True to disable this KeyNav instance (defaults to false)
14186      */
14187     disabled : false,
14188     /**
14189      * @cfg {String} defaultEventAction
14190      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14191      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14192      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14193      */
14194     defaultEventAction: "stopEvent",
14195     /**
14196      * @cfg {Boolean} forceKeyDown
14197      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14198      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14199      * handle keydown instead of keypress.
14200      */
14201     forceKeyDown : false,
14202
14203     // private
14204     prepareEvent : function(e){
14205         var k = e.getKey();
14206         var h = this.keyToHandler[k];
14207         //if(h && this[h]){
14208         //    e.stopPropagation();
14209         //}
14210         if(Roo.isSafari && h && k >= 37 && k <= 40){
14211             e.stopEvent();
14212         }
14213     },
14214
14215     // private
14216     relay : function(e){
14217         var k = e.getKey();
14218         var h = this.keyToHandler[k];
14219         if(h && this[h]){
14220             if(this.doRelay(e, this[h], h) !== true){
14221                 e[this.defaultEventAction]();
14222             }
14223         }
14224     },
14225
14226     // private
14227     doRelay : function(e, h, hname){
14228         return h.call(this.scope || this, e);
14229     },
14230
14231     // possible handlers
14232     enter : false,
14233     left : false,
14234     right : false,
14235     up : false,
14236     down : false,
14237     tab : false,
14238     esc : false,
14239     pageUp : false,
14240     pageDown : false,
14241     del : false,
14242     home : false,
14243     end : false,
14244
14245     // quick lookup hash
14246     keyToHandler : {
14247         37 : "left",
14248         39 : "right",
14249         38 : "up",
14250         40 : "down",
14251         33 : "pageUp",
14252         34 : "pageDown",
14253         46 : "del",
14254         36 : "home",
14255         35 : "end",
14256         13 : "enter",
14257         27 : "esc",
14258         9  : "tab"
14259     },
14260
14261         /**
14262          * Enable this KeyNav
14263          */
14264         enable: function(){
14265                 if(this.disabled){
14266             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14267             // the EventObject will normalize Safari automatically
14268             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14269                 this.el.on("keydown", this.relay,  this);
14270             }else{
14271                 this.el.on("keydown", this.prepareEvent,  this);
14272                 this.el.on("keypress", this.relay,  this);
14273             }
14274                     this.disabled = false;
14275                 }
14276         },
14277
14278         /**
14279          * Disable this KeyNav
14280          */
14281         disable: function(){
14282                 if(!this.disabled){
14283                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14284                 this.el.un("keydown", this.relay);
14285             }else{
14286                 this.el.un("keydown", this.prepareEvent);
14287                 this.el.un("keypress", this.relay);
14288             }
14289                     this.disabled = true;
14290                 }
14291         }
14292 };/*
14293  * Based on:
14294  * Ext JS Library 1.1.1
14295  * Copyright(c) 2006-2007, Ext JS, LLC.
14296  *
14297  * Originally Released Under LGPL - original licence link has changed is not relivant.
14298  *
14299  * Fork - LGPL
14300  * <script type="text/javascript">
14301  */
14302
14303  
14304 /**
14305  * @class Roo.KeyMap
14306  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14307  * The constructor accepts the same config object as defined by {@link #addBinding}.
14308  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14309  * combination it will call the function with this signature (if the match is a multi-key
14310  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14311  * A KeyMap can also handle a string representation of keys.<br />
14312  * Usage:
14313  <pre><code>
14314 // map one key by key code
14315 var map = new Roo.KeyMap("my-element", {
14316     key: 13, // or Roo.EventObject.ENTER
14317     fn: myHandler,
14318     scope: myObject
14319 });
14320
14321 // map multiple keys to one action by string
14322 var map = new Roo.KeyMap("my-element", {
14323     key: "a\r\n\t",
14324     fn: myHandler,
14325     scope: myObject
14326 });
14327
14328 // map multiple keys to multiple actions by strings and array of codes
14329 var map = new Roo.KeyMap("my-element", [
14330     {
14331         key: [10,13],
14332         fn: function(){ alert("Return was pressed"); }
14333     }, {
14334         key: "abc",
14335         fn: function(){ alert('a, b or c was pressed'); }
14336     }, {
14337         key: "\t",
14338         ctrl:true,
14339         shift:true,
14340         fn: function(){ alert('Control + shift + tab was pressed.'); }
14341     }
14342 ]);
14343 </code></pre>
14344  * <b>Note: A KeyMap starts enabled</b>
14345  * @constructor
14346  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14347  * @param {Object} config The config (see {@link #addBinding})
14348  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14349  */
14350 Roo.KeyMap = function(el, config, eventName){
14351     this.el  = Roo.get(el);
14352     this.eventName = eventName || "keydown";
14353     this.bindings = [];
14354     if(config){
14355         this.addBinding(config);
14356     }
14357     this.enable();
14358 };
14359
14360 Roo.KeyMap.prototype = {
14361     /**
14362      * True to stop the event from bubbling and prevent the default browser action if the
14363      * key was handled by the KeyMap (defaults to false)
14364      * @type Boolean
14365      */
14366     stopEvent : false,
14367
14368     /**
14369      * Add a new binding to this KeyMap. The following config object properties are supported:
14370      * <pre>
14371 Property    Type             Description
14372 ----------  ---------------  ----------------------------------------------------------------------
14373 key         String/Array     A single keycode or an array of keycodes to handle
14374 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14375 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14376 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14377 fn          Function         The function to call when KeyMap finds the expected key combination
14378 scope       Object           The scope of the callback function
14379 </pre>
14380      *
14381      * Usage:
14382      * <pre><code>
14383 // Create a KeyMap
14384 var map = new Roo.KeyMap(document, {
14385     key: Roo.EventObject.ENTER,
14386     fn: handleKey,
14387     scope: this
14388 });
14389
14390 //Add a new binding to the existing KeyMap later
14391 map.addBinding({
14392     key: 'abc',
14393     shift: true,
14394     fn: handleKey,
14395     scope: this
14396 });
14397 </code></pre>
14398      * @param {Object/Array} config A single KeyMap config or an array of configs
14399      */
14400         addBinding : function(config){
14401         if(config instanceof Array){
14402             for(var i = 0, len = config.length; i < len; i++){
14403                 this.addBinding(config[i]);
14404             }
14405             return;
14406         }
14407         var keyCode = config.key,
14408             shift = config.shift, 
14409             ctrl = config.ctrl, 
14410             alt = config.alt,
14411             fn = config.fn,
14412             scope = config.scope;
14413         if(typeof keyCode == "string"){
14414             var ks = [];
14415             var keyString = keyCode.toUpperCase();
14416             for(var j = 0, len = keyString.length; j < len; j++){
14417                 ks.push(keyString.charCodeAt(j));
14418             }
14419             keyCode = ks;
14420         }
14421         var keyArray = keyCode instanceof Array;
14422         var handler = function(e){
14423             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14424                 var k = e.getKey();
14425                 if(keyArray){
14426                     for(var i = 0, len = keyCode.length; i < len; i++){
14427                         if(keyCode[i] == k){
14428                           if(this.stopEvent){
14429                               e.stopEvent();
14430                           }
14431                           fn.call(scope || window, k, e);
14432                           return;
14433                         }
14434                     }
14435                 }else{
14436                     if(k == keyCode){
14437                         if(this.stopEvent){
14438                            e.stopEvent();
14439                         }
14440                         fn.call(scope || window, k, e);
14441                     }
14442                 }
14443             }
14444         };
14445         this.bindings.push(handler);  
14446         },
14447
14448     /**
14449      * Shorthand for adding a single key listener
14450      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14451      * following options:
14452      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14453      * @param {Function} fn The function to call
14454      * @param {Object} scope (optional) The scope of the function
14455      */
14456     on : function(key, fn, scope){
14457         var keyCode, shift, ctrl, alt;
14458         if(typeof key == "object" && !(key instanceof Array)){
14459             keyCode = key.key;
14460             shift = key.shift;
14461             ctrl = key.ctrl;
14462             alt = key.alt;
14463         }else{
14464             keyCode = key;
14465         }
14466         this.addBinding({
14467             key: keyCode,
14468             shift: shift,
14469             ctrl: ctrl,
14470             alt: alt,
14471             fn: fn,
14472             scope: scope
14473         })
14474     },
14475
14476     // private
14477     handleKeyDown : function(e){
14478             if(this.enabled){ //just in case
14479             var b = this.bindings;
14480             for(var i = 0, len = b.length; i < len; i++){
14481                 b[i].call(this, e);
14482             }
14483             }
14484         },
14485         
14486         /**
14487          * Returns true if this KeyMap is enabled
14488          * @return {Boolean} 
14489          */
14490         isEnabled : function(){
14491             return this.enabled;  
14492         },
14493         
14494         /**
14495          * Enables this KeyMap
14496          */
14497         enable: function(){
14498                 if(!this.enabled){
14499                     this.el.on(this.eventName, this.handleKeyDown, this);
14500                     this.enabled = true;
14501                 }
14502         },
14503
14504         /**
14505          * Disable this KeyMap
14506          */
14507         disable: function(){
14508                 if(this.enabled){
14509                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14510                     this.enabled = false;
14511                 }
14512         }
14513 };/*
14514  * Based on:
14515  * Ext JS Library 1.1.1
14516  * Copyright(c) 2006-2007, Ext JS, LLC.
14517  *
14518  * Originally Released Under LGPL - original licence link has changed is not relivant.
14519  *
14520  * Fork - LGPL
14521  * <script type="text/javascript">
14522  */
14523
14524  
14525 /**
14526  * @class Roo.util.TextMetrics
14527  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14528  * wide, in pixels, a given block of text will be.
14529  * @singleton
14530  */
14531 Roo.util.TextMetrics = function(){
14532     var shared;
14533     return {
14534         /**
14535          * Measures the size of the specified text
14536          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14537          * that can affect the size of the rendered text
14538          * @param {String} text The text to measure
14539          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14540          * in order to accurately measure the text height
14541          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14542          */
14543         measure : function(el, text, fixedWidth){
14544             if(!shared){
14545                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14546             }
14547             shared.bind(el);
14548             shared.setFixedWidth(fixedWidth || 'auto');
14549             return shared.getSize(text);
14550         },
14551
14552         /**
14553          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14554          * the overhead of multiple calls to initialize the style properties on each measurement.
14555          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14556          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14557          * in order to accurately measure the text height
14558          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14559          */
14560         createInstance : function(el, fixedWidth){
14561             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14562         }
14563     };
14564 }();
14565
14566  
14567
14568 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14569     var ml = new Roo.Element(document.createElement('div'));
14570     document.body.appendChild(ml.dom);
14571     ml.position('absolute');
14572     ml.setLeftTop(-1000, -1000);
14573     ml.hide();
14574
14575     if(fixedWidth){
14576         ml.setWidth(fixedWidth);
14577     }
14578      
14579     var instance = {
14580         /**
14581          * Returns the size of the specified text based on the internal element's style and width properties
14582          * @memberOf Roo.util.TextMetrics.Instance#
14583          * @param {String} text The text to measure
14584          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14585          */
14586         getSize : function(text){
14587             ml.update(text);
14588             var s = ml.getSize();
14589             ml.update('');
14590             return s;
14591         },
14592
14593         /**
14594          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14595          * that can affect the size of the rendered text
14596          * @memberOf Roo.util.TextMetrics.Instance#
14597          * @param {String/HTMLElement} el The element, dom node or id
14598          */
14599         bind : function(el){
14600             ml.setStyle(
14601                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14602             );
14603         },
14604
14605         /**
14606          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14607          * to set a fixed width in order to accurately measure the text height.
14608          * @memberOf Roo.util.TextMetrics.Instance#
14609          * @param {Number} width The width to set on the element
14610          */
14611         setFixedWidth : function(width){
14612             ml.setWidth(width);
14613         },
14614
14615         /**
14616          * Returns the measured width of the specified text
14617          * @memberOf Roo.util.TextMetrics.Instance#
14618          * @param {String} text The text to measure
14619          * @return {Number} width The width in pixels
14620          */
14621         getWidth : function(text){
14622             ml.dom.style.width = 'auto';
14623             return this.getSize(text).width;
14624         },
14625
14626         /**
14627          * Returns the measured height of the specified text.  For multiline text, be sure to call
14628          * {@link #setFixedWidth} if necessary.
14629          * @memberOf Roo.util.TextMetrics.Instance#
14630          * @param {String} text The text to measure
14631          * @return {Number} height The height in pixels
14632          */
14633         getHeight : function(text){
14634             return this.getSize(text).height;
14635         }
14636     };
14637
14638     instance.bind(bindTo);
14639
14640     return instance;
14641 };
14642
14643 // backwards compat
14644 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14645  * Based on:
14646  * Ext JS Library 1.1.1
14647  * Copyright(c) 2006-2007, Ext JS, LLC.
14648  *
14649  * Originally Released Under LGPL - original licence link has changed is not relivant.
14650  *
14651  * Fork - LGPL
14652  * <script type="text/javascript">
14653  */
14654
14655 /**
14656  * @class Roo.state.Provider
14657  * Abstract base class for state provider implementations. This class provides methods
14658  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14659  * Provider interface.
14660  */
14661 Roo.state.Provider = function(){
14662     /**
14663      * @event statechange
14664      * Fires when a state change occurs.
14665      * @param {Provider} this This state provider
14666      * @param {String} key The state key which was changed
14667      * @param {String} value The encoded value for the state
14668      */
14669     this.addEvents({
14670         "statechange": true
14671     });
14672     this.state = {};
14673     Roo.state.Provider.superclass.constructor.call(this);
14674 };
14675 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14676     /**
14677      * Returns the current value for a key
14678      * @param {String} name The key name
14679      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14680      * @return {Mixed} The state data
14681      */
14682     get : function(name, defaultValue){
14683         return typeof this.state[name] == "undefined" ?
14684             defaultValue : this.state[name];
14685     },
14686     
14687     /**
14688      * Clears a value from the state
14689      * @param {String} name The key name
14690      */
14691     clear : function(name){
14692         delete this.state[name];
14693         this.fireEvent("statechange", this, name, null);
14694     },
14695     
14696     /**
14697      * Sets the value for a key
14698      * @param {String} name The key name
14699      * @param {Mixed} value The value to set
14700      */
14701     set : function(name, value){
14702         this.state[name] = value;
14703         this.fireEvent("statechange", this, name, value);
14704     },
14705     
14706     /**
14707      * Decodes a string previously encoded with {@link #encodeValue}.
14708      * @param {String} value The value to decode
14709      * @return {Mixed} The decoded value
14710      */
14711     decodeValue : function(cookie){
14712         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14713         var matches = re.exec(unescape(cookie));
14714         if(!matches || !matches[1]) return; // non state cookie
14715         var type = matches[1];
14716         var v = matches[2];
14717         switch(type){
14718             case "n":
14719                 return parseFloat(v);
14720             case "d":
14721                 return new Date(Date.parse(v));
14722             case "b":
14723                 return (v == "1");
14724             case "a":
14725                 var all = [];
14726                 var values = v.split("^");
14727                 for(var i = 0, len = values.length; i < len; i++){
14728                     all.push(this.decodeValue(values[i]));
14729                 }
14730                 return all;
14731            case "o":
14732                 var all = {};
14733                 var values = v.split("^");
14734                 for(var i = 0, len = values.length; i < len; i++){
14735                     var kv = values[i].split("=");
14736                     all[kv[0]] = this.decodeValue(kv[1]);
14737                 }
14738                 return all;
14739            default:
14740                 return v;
14741         }
14742     },
14743     
14744     /**
14745      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14746      * @param {Mixed} value The value to encode
14747      * @return {String} The encoded value
14748      */
14749     encodeValue : function(v){
14750         var enc;
14751         if(typeof v == "number"){
14752             enc = "n:" + v;
14753         }else if(typeof v == "boolean"){
14754             enc = "b:" + (v ? "1" : "0");
14755         }else if(v instanceof Date){
14756             enc = "d:" + v.toGMTString();
14757         }else if(v instanceof Array){
14758             var flat = "";
14759             for(var i = 0, len = v.length; i < len; i++){
14760                 flat += this.encodeValue(v[i]);
14761                 if(i != len-1) flat += "^";
14762             }
14763             enc = "a:" + flat;
14764         }else if(typeof v == "object"){
14765             var flat = "";
14766             for(var key in v){
14767                 if(typeof v[key] != "function"){
14768                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14769                 }
14770             }
14771             enc = "o:" + flat.substring(0, flat.length-1);
14772         }else{
14773             enc = "s:" + v;
14774         }
14775         return escape(enc);        
14776     }
14777 });
14778
14779 /*
14780  * Based on:
14781  * Ext JS Library 1.1.1
14782  * Copyright(c) 2006-2007, Ext JS, LLC.
14783  *
14784  * Originally Released Under LGPL - original licence link has changed is not relivant.
14785  *
14786  * Fork - LGPL
14787  * <script type="text/javascript">
14788  */
14789 /**
14790  * @class Roo.state.Manager
14791  * This is the global state manager. By default all components that are "state aware" check this class
14792  * for state information if you don't pass them a custom state provider. In order for this class
14793  * to be useful, it must be initialized with a provider when your application initializes.
14794  <pre><code>
14795 // in your initialization function
14796 init : function(){
14797    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14798    ...
14799    // supposed you have a {@link Roo.BorderLayout}
14800    var layout = new Roo.BorderLayout(...);
14801    layout.restoreState();
14802    // or a {Roo.BasicDialog}
14803    var dialog = new Roo.BasicDialog(...);
14804    dialog.restoreState();
14805  </code></pre>
14806  * @singleton
14807  */
14808 Roo.state.Manager = function(){
14809     var provider = new Roo.state.Provider();
14810     
14811     return {
14812         /**
14813          * Configures the default state provider for your application
14814          * @param {Provider} stateProvider The state provider to set
14815          */
14816         setProvider : function(stateProvider){
14817             provider = stateProvider;
14818         },
14819         
14820         /**
14821          * Returns the current value for a key
14822          * @param {String} name The key name
14823          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14824          * @return {Mixed} The state data
14825          */
14826         get : function(key, defaultValue){
14827             return provider.get(key, defaultValue);
14828         },
14829         
14830         /**
14831          * Sets the value for a key
14832          * @param {String} name The key name
14833          * @param {Mixed} value The state data
14834          */
14835          set : function(key, value){
14836             provider.set(key, value);
14837         },
14838         
14839         /**
14840          * Clears a value from the state
14841          * @param {String} name The key name
14842          */
14843         clear : function(key){
14844             provider.clear(key);
14845         },
14846         
14847         /**
14848          * Gets the currently configured state provider
14849          * @return {Provider} The state provider
14850          */
14851         getProvider : function(){
14852             return provider;
14853         }
14854     };
14855 }();
14856 /*
14857  * Based on:
14858  * Ext JS Library 1.1.1
14859  * Copyright(c) 2006-2007, Ext JS, LLC.
14860  *
14861  * Originally Released Under LGPL - original licence link has changed is not relivant.
14862  *
14863  * Fork - LGPL
14864  * <script type="text/javascript">
14865  */
14866 /**
14867  * @class Roo.state.CookieProvider
14868  * @extends Roo.state.Provider
14869  * The default Provider implementation which saves state via cookies.
14870  * <br />Usage:
14871  <pre><code>
14872    var cp = new Roo.state.CookieProvider({
14873        path: "/cgi-bin/",
14874        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14875        domain: "roojs.com"
14876    })
14877    Roo.state.Manager.setProvider(cp);
14878  </code></pre>
14879  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14880  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14881  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14882  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14883  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14884  * domain the page is running on including the 'www' like 'www.roojs.com')
14885  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14886  * @constructor
14887  * Create a new CookieProvider
14888  * @param {Object} config The configuration object
14889  */
14890 Roo.state.CookieProvider = function(config){
14891     Roo.state.CookieProvider.superclass.constructor.call(this);
14892     this.path = "/";
14893     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14894     this.domain = null;
14895     this.secure = false;
14896     Roo.apply(this, config);
14897     this.state = this.readCookies();
14898 };
14899
14900 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14901     // private
14902     set : function(name, value){
14903         if(typeof value == "undefined" || value === null){
14904             this.clear(name);
14905             return;
14906         }
14907         this.setCookie(name, value);
14908         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14909     },
14910
14911     // private
14912     clear : function(name){
14913         this.clearCookie(name);
14914         Roo.state.CookieProvider.superclass.clear.call(this, name);
14915     },
14916
14917     // private
14918     readCookies : function(){
14919         var cookies = {};
14920         var c = document.cookie + ";";
14921         var re = /\s?(.*?)=(.*?);/g;
14922         var matches;
14923         while((matches = re.exec(c)) != null){
14924             var name = matches[1];
14925             var value = matches[2];
14926             if(name && name.substring(0,3) == "ys-"){
14927                 cookies[name.substr(3)] = this.decodeValue(value);
14928             }
14929         }
14930         return cookies;
14931     },
14932
14933     // private
14934     setCookie : function(name, value){
14935         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14936            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14937            ((this.path == null) ? "" : ("; path=" + this.path)) +
14938            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14939            ((this.secure == true) ? "; secure" : "");
14940     },
14941
14942     // private
14943     clearCookie : function(name){
14944         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14945            ((this.path == null) ? "" : ("; path=" + this.path)) +
14946            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14947            ((this.secure == true) ? "; secure" : "");
14948     }
14949 });