roojs-core.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         el = Roo.getDom(el);
4500         if (o.ns) {
4501           
4502             while (el.childNodes.length) {
4503                 el.removeChild(el.firstChild);
4504             }
4505             createDom(o, el);
4506         } else {
4507             el.innerHTML = createHtml(o);   
4508         }
4509         
4510         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4511     },
4512
4513     /**
4514      * Creates a new Roo.DomHelper.Template from the Dom object spec
4515      * @param {Object} o The Dom object spec (and children)
4516      * @return {Roo.DomHelper.Template} The new template
4517      */
4518     createTemplate : function(o){
4519         var html = createHtml(o);
4520         return new Roo.Template(html);
4521     }
4522     };
4523 }();
4524 /*
4525  * Based on:
4526  * Ext JS Library 1.1.1
4527  * Copyright(c) 2006-2007, Ext JS, LLC.
4528  *
4529  * Originally Released Under LGPL - original licence link has changed is not relivant.
4530  *
4531  * Fork - LGPL
4532  * <script type="text/javascript">
4533  */
4534  
4535 /**
4536 * @class Roo.Template
4537 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4538 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4539 * Usage:
4540 <pre><code>
4541 var t = new Roo.Template({
4542     html :  '&lt;div name="{id}"&gt;' + 
4543         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4544         '&lt;/div&gt;',
4545     myformat: function (value, allValues) {
4546         return 'XX' + value;
4547     }
4548 });
4549 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4550 </code></pre>
4551 * For more information see this blog post with examples:
4552 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4553      - Create Elements using DOM, HTML fragments and Templates</a>. 
4554 * @constructor
4555 * @param {Object} cfg - Configuration object.
4556 */
4557 Roo.Template = function(cfg){
4558     // BC!
4559     if(cfg instanceof Array){
4560         cfg = cfg.join("");
4561     }else if(arguments.length > 1){
4562         cfg = Array.prototype.join.call(arguments, "");
4563     }
4564     
4565     
4566     if (typeof(cfg) == 'object') {
4567         Roo.apply(this,cfg)
4568     } else {
4569         // bc
4570         this.html = cfg;
4571     }
4572     if (this.url) {
4573         this.load();
4574     }
4575     
4576 };
4577 Roo.Template.prototype = {
4578     
4579     /**
4580      * @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..
4581      *                    it should be fixed so that template is observable...
4582      */
4583     url : false,
4584     /**
4585      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4586      */
4587     html : '',
4588     /**
4589      * Returns an HTML fragment of this template with the specified values applied.
4590      * @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'})
4591      * @return {String} The HTML fragment
4592      */
4593     applyTemplate : function(values){
4594         try {
4595            
4596             if(this.compiled){
4597                 return this.compiled(values);
4598             }
4599             var useF = this.disableFormats !== true;
4600             var fm = Roo.util.Format, tpl = this;
4601             var fn = function(m, name, format, args){
4602                 if(format && useF){
4603                     if(format.substr(0, 5) == "this."){
4604                         return tpl.call(format.substr(5), values[name], values);
4605                     }else{
4606                         if(args){
4607                             // quoted values are required for strings in compiled templates, 
4608                             // but for non compiled we need to strip them
4609                             // quoted reversed for jsmin
4610                             var re = /^\s*['"](.*)["']\s*$/;
4611                             args = args.split(',');
4612                             for(var i = 0, len = args.length; i < len; i++){
4613                                 args[i] = args[i].replace(re, "$1");
4614                             }
4615                             args = [values[name]].concat(args);
4616                         }else{
4617                             args = [values[name]];
4618                         }
4619                         return fm[format].apply(fm, args);
4620                     }
4621                 }else{
4622                     return values[name] !== undefined ? values[name] : "";
4623                 }
4624             };
4625             return this.html.replace(this.re, fn);
4626         } catch (e) {
4627             Roo.log(e);
4628             throw e;
4629         }
4630          
4631     },
4632     
4633     loading : false,
4634       
4635     load : function ()
4636     {
4637          
4638         if (this.loading) {
4639             return;
4640         }
4641         var _t = this;
4642         
4643         this.loading = true;
4644         this.compiled = false;
4645         
4646         var cx = new Roo.data.Connection();
4647         cx.request({
4648             url : this.url,
4649             method : 'GET',
4650             success : function (response) {
4651                 _t.loading = false;
4652                 _t.html = response.responseText;
4653                 _t.url = false;
4654                 _t.compile();
4655              },
4656             failure : function(response) {
4657                 Roo.log("Template failed to load from " + _t.url);
4658                 _t.loading = false;
4659             }
4660         });
4661     },
4662
4663     /**
4664      * Sets the HTML used as the template and optionally compiles it.
4665      * @param {String} html
4666      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4667      * @return {Roo.Template} this
4668      */
4669     set : function(html, compile){
4670         this.html = html;
4671         this.compiled = null;
4672         if(compile){
4673             this.compile();
4674         }
4675         return this;
4676     },
4677     
4678     /**
4679      * True to disable format functions (defaults to false)
4680      * @type Boolean
4681      */
4682     disableFormats : false,
4683     
4684     /**
4685     * The regular expression used to match template variables 
4686     * @type RegExp
4687     * @property 
4688     */
4689     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4690     
4691     /**
4692      * Compiles the template into an internal function, eliminating the RegEx overhead.
4693      * @return {Roo.Template} this
4694      */
4695     compile : function(){
4696         var fm = Roo.util.Format;
4697         var useF = this.disableFormats !== true;
4698         var sep = Roo.isGecko ? "+" : ",";
4699         var fn = function(m, name, format, args){
4700             if(format && useF){
4701                 args = args ? ',' + args : "";
4702                 if(format.substr(0, 5) != "this."){
4703                     format = "fm." + format + '(';
4704                 }else{
4705                     format = 'this.call("'+ format.substr(5) + '", ';
4706                     args = ", values";
4707                 }
4708             }else{
4709                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4710             }
4711             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4712         };
4713         var body;
4714         // branched to use + in gecko and [].join() in others
4715         if(Roo.isGecko){
4716             body = "this.compiled = function(values){ return '" +
4717                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4718                     "';};";
4719         }else{
4720             body = ["this.compiled = function(values){ return ['"];
4721             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4722             body.push("'].join('');};");
4723             body = body.join('');
4724         }
4725         /**
4726          * eval:var:values
4727          * eval:var:fm
4728          */
4729         eval(body);
4730         return this;
4731     },
4732     
4733     // private function used to call members
4734     call : function(fnName, value, allValues){
4735         return this[fnName](value, allValues);
4736     },
4737     
4738     /**
4739      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4740      * @param {String/HTMLElement/Roo.Element} el The context element
4741      * @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'})
4742      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4743      * @return {HTMLElement/Roo.Element} The new node or Element
4744      */
4745     insertFirst: function(el, values, returnElement){
4746         return this.doInsert('afterBegin', el, values, returnElement);
4747     },
4748
4749     /**
4750      * Applies the supplied values to the template and inserts the new node(s) before el.
4751      * @param {String/HTMLElement/Roo.Element} el The context element
4752      * @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'})
4753      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4754      * @return {HTMLElement/Roo.Element} The new node or Element
4755      */
4756     insertBefore: function(el, values, returnElement){
4757         return this.doInsert('beforeBegin', el, values, returnElement);
4758     },
4759
4760     /**
4761      * Applies the supplied values to the template and inserts the new node(s) after el.
4762      * @param {String/HTMLElement/Roo.Element} el The context element
4763      * @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'})
4764      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4765      * @return {HTMLElement/Roo.Element} The new node or Element
4766      */
4767     insertAfter : function(el, values, returnElement){
4768         return this.doInsert('afterEnd', el, values, returnElement);
4769     },
4770     
4771     /**
4772      * Applies the supplied values to the template and appends the new node(s) to el.
4773      * @param {String/HTMLElement/Roo.Element} el The context element
4774      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4775      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4776      * @return {HTMLElement/Roo.Element} The new node or Element
4777      */
4778     append : function(el, values, returnElement){
4779         return this.doInsert('beforeEnd', el, values, returnElement);
4780     },
4781
4782     doInsert : function(where, el, values, returnEl){
4783         el = Roo.getDom(el);
4784         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4785         return returnEl ? Roo.get(newNode, true) : newNode;
4786     },
4787
4788     /**
4789      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4790      * @param {String/HTMLElement/Roo.Element} el The context element
4791      * @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'})
4792      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4793      * @return {HTMLElement/Roo.Element} The new node or Element
4794      */
4795     overwrite : function(el, values, returnElement){
4796         el = Roo.getDom(el);
4797         el.innerHTML = this.applyTemplate(values);
4798         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4799     }
4800 };
4801 /**
4802  * Alias for {@link #applyTemplate}
4803  * @method
4804  */
4805 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4806
4807 // backwards compat
4808 Roo.DomHelper.Template = Roo.Template;
4809
4810 /**
4811  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4812  * @param {String/HTMLElement} el A DOM element or its id
4813  * @returns {Roo.Template} The created template
4814  * @static
4815  */
4816 Roo.Template.from = function(el){
4817     el = Roo.getDom(el);
4818     return new Roo.Template(el.value || el.innerHTML);
4819 };/*
4820  * Based on:
4821  * Ext JS Library 1.1.1
4822  * Copyright(c) 2006-2007, Ext JS, LLC.
4823  *
4824  * Originally Released Under LGPL - original licence link has changed is not relivant.
4825  *
4826  * Fork - LGPL
4827  * <script type="text/javascript">
4828  */
4829  
4830
4831 /*
4832  * This is code is also distributed under MIT license for use
4833  * with jQuery and prototype JavaScript libraries.
4834  */
4835 /**
4836  * @class Roo.DomQuery
4837 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).
4838 <p>
4839 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>
4840
4841 <p>
4842 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.
4843 </p>
4844 <h4>Element Selectors:</h4>
4845 <ul class="list">
4846     <li> <b>*</b> any element</li>
4847     <li> <b>E</b> an element with the tag E</li>
4848     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4849     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4850     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4851     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4852 </ul>
4853 <h4>Attribute Selectors:</h4>
4854 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4855 <ul class="list">
4856     <li> <b>E[foo]</b> has an attribute "foo"</li>
4857     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4858     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4859     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4860     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4861     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4862     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4863 </ul>
4864 <h4>Pseudo Classes:</h4>
4865 <ul class="list">
4866     <li> <b>E:first-child</b> E is the first child of its parent</li>
4867     <li> <b>E:last-child</b> E is the last child of its parent</li>
4868     <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>
4869     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4870     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4871     <li> <b>E:only-child</b> E is the only child of its parent</li>
4872     <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>
4873     <li> <b>E:first</b> the first E in the resultset</li>
4874     <li> <b>E:last</b> the last E in the resultset</li>
4875     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4876     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4877     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4878     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4879     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4880     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4881     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4882     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4883     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4884 </ul>
4885 <h4>CSS Value Selectors:</h4>
4886 <ul class="list">
4887     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4888     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4889     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4890     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4891     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4892     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4893 </ul>
4894  * @singleton
4895  */
4896 Roo.DomQuery = function(){
4897     var cache = {}, simpleCache = {}, valueCache = {};
4898     var nonSpace = /\S/;
4899     var trimRe = /^\s+|\s+$/g;
4900     var tplRe = /\{(\d+)\}/g;
4901     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4902     var tagTokenRe = /^(#)?([\w-\*]+)/;
4903     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4904
4905     function child(p, index){
4906         var i = 0;
4907         var n = p.firstChild;
4908         while(n){
4909             if(n.nodeType == 1){
4910                if(++i == index){
4911                    return n;
4912                }
4913             }
4914             n = n.nextSibling;
4915         }
4916         return null;
4917     };
4918
4919     function next(n){
4920         while((n = n.nextSibling) && n.nodeType != 1);
4921         return n;
4922     };
4923
4924     function prev(n){
4925         while((n = n.previousSibling) && n.nodeType != 1);
4926         return n;
4927     };
4928
4929     function children(d){
4930         var n = d.firstChild, ni = -1;
4931             while(n){
4932                 var nx = n.nextSibling;
4933                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4934                     d.removeChild(n);
4935                 }else{
4936                     n.nodeIndex = ++ni;
4937                 }
4938                 n = nx;
4939             }
4940             return this;
4941         };
4942
4943     function byClassName(c, a, v){
4944         if(!v){
4945             return c;
4946         }
4947         var r = [], ri = -1, cn;
4948         for(var i = 0, ci; ci = c[i]; i++){
4949             if((' '+ci.className+' ').indexOf(v) != -1){
4950                 r[++ri] = ci;
4951             }
4952         }
4953         return r;
4954     };
4955
4956     function attrValue(n, attr){
4957         if(!n.tagName && typeof n.length != "undefined"){
4958             n = n[0];
4959         }
4960         if(!n){
4961             return null;
4962         }
4963         if(attr == "for"){
4964             return n.htmlFor;
4965         }
4966         if(attr == "class" || attr == "className"){
4967             return n.className;
4968         }
4969         return n.getAttribute(attr) || n[attr];
4970
4971     };
4972
4973     function getNodes(ns, mode, tagName){
4974         var result = [], ri = -1, cs;
4975         if(!ns){
4976             return result;
4977         }
4978         tagName = tagName || "*";
4979         if(typeof ns.getElementsByTagName != "undefined"){
4980             ns = [ns];
4981         }
4982         if(!mode){
4983             for(var i = 0, ni; ni = ns[i]; i++){
4984                 cs = ni.getElementsByTagName(tagName);
4985                 for(var j = 0, ci; ci = cs[j]; j++){
4986                     result[++ri] = ci;
4987                 }
4988             }
4989         }else if(mode == "/" || mode == ">"){
4990             var utag = tagName.toUpperCase();
4991             for(var i = 0, ni, cn; ni = ns[i]; i++){
4992                 cn = ni.children || ni.childNodes;
4993                 for(var j = 0, cj; cj = cn[j]; j++){
4994                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4995                         result[++ri] = cj;
4996                     }
4997                 }
4998             }
4999         }else if(mode == "+"){
5000             var utag = tagName.toUpperCase();
5001             for(var i = 0, n; n = ns[i]; i++){
5002                 while((n = n.nextSibling) && n.nodeType != 1);
5003                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5004                     result[++ri] = n;
5005                 }
5006             }
5007         }else if(mode == "~"){
5008             for(var i = 0, n; n = ns[i]; i++){
5009                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5010                 if(n){
5011                     result[++ri] = n;
5012                 }
5013             }
5014         }
5015         return result;
5016     };
5017
5018     function concat(a, b){
5019         if(b.slice){
5020             return a.concat(b);
5021         }
5022         for(var i = 0, l = b.length; i < l; i++){
5023             a[a.length] = b[i];
5024         }
5025         return a;
5026     }
5027
5028     function byTag(cs, tagName){
5029         if(cs.tagName || cs == document){
5030             cs = [cs];
5031         }
5032         if(!tagName){
5033             return cs;
5034         }
5035         var r = [], ri = -1;
5036         tagName = tagName.toLowerCase();
5037         for(var i = 0, ci; ci = cs[i]; i++){
5038             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5039                 r[++ri] = ci;
5040             }
5041         }
5042         return r;
5043     };
5044
5045     function byId(cs, attr, id){
5046         if(cs.tagName || cs == document){
5047             cs = [cs];
5048         }
5049         if(!id){
5050             return cs;
5051         }
5052         var r = [], ri = -1;
5053         for(var i = 0,ci; ci = cs[i]; i++){
5054             if(ci && ci.id == id){
5055                 r[++ri] = ci;
5056                 return r;
5057             }
5058         }
5059         return r;
5060     };
5061
5062     function byAttribute(cs, attr, value, op, custom){
5063         var r = [], ri = -1, st = custom=="{";
5064         var f = Roo.DomQuery.operators[op];
5065         for(var i = 0, ci; ci = cs[i]; i++){
5066             var a;
5067             if(st){
5068                 a = Roo.DomQuery.getStyle(ci, attr);
5069             }
5070             else if(attr == "class" || attr == "className"){
5071                 a = ci.className;
5072             }else if(attr == "for"){
5073                 a = ci.htmlFor;
5074             }else if(attr == "href"){
5075                 a = ci.getAttribute("href", 2);
5076             }else{
5077                 a = ci.getAttribute(attr);
5078             }
5079             if((f && f(a, value)) || (!f && a)){
5080                 r[++ri] = ci;
5081             }
5082         }
5083         return r;
5084     };
5085
5086     function byPseudo(cs, name, value){
5087         return Roo.DomQuery.pseudos[name](cs, value);
5088     };
5089
5090     // This is for IE MSXML which does not support expandos.
5091     // IE runs the same speed using setAttribute, however FF slows way down
5092     // and Safari completely fails so they need to continue to use expandos.
5093     var isIE = window.ActiveXObject ? true : false;
5094
5095     // this eval is stop the compressor from
5096     // renaming the variable to something shorter
5097     
5098     /** eval:var:batch */
5099     var batch = 30803; 
5100
5101     var key = 30803;
5102
5103     function nodupIEXml(cs){
5104         var d = ++key;
5105         cs[0].setAttribute("_nodup", d);
5106         var r = [cs[0]];
5107         for(var i = 1, len = cs.length; i < len; i++){
5108             var c = cs[i];
5109             if(!c.getAttribute("_nodup") != d){
5110                 c.setAttribute("_nodup", d);
5111                 r[r.length] = c;
5112             }
5113         }
5114         for(var i = 0, len = cs.length; i < len; i++){
5115             cs[i].removeAttribute("_nodup");
5116         }
5117         return r;
5118     }
5119
5120     function nodup(cs){
5121         if(!cs){
5122             return [];
5123         }
5124         var len = cs.length, c, i, r = cs, cj, ri = -1;
5125         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5126             return cs;
5127         }
5128         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5129             return nodupIEXml(cs);
5130         }
5131         var d = ++key;
5132         cs[0]._nodup = d;
5133         for(i = 1; c = cs[i]; i++){
5134             if(c._nodup != d){
5135                 c._nodup = d;
5136             }else{
5137                 r = [];
5138                 for(var j = 0; j < i; j++){
5139                     r[++ri] = cs[j];
5140                 }
5141                 for(j = i+1; cj = cs[j]; j++){
5142                     if(cj._nodup != d){
5143                         cj._nodup = d;
5144                         r[++ri] = cj;
5145                     }
5146                 }
5147                 return r;
5148             }
5149         }
5150         return r;
5151     }
5152
5153     function quickDiffIEXml(c1, c2){
5154         var d = ++key;
5155         for(var i = 0, len = c1.length; i < len; i++){
5156             c1[i].setAttribute("_qdiff", d);
5157         }
5158         var r = [];
5159         for(var i = 0, len = c2.length; i < len; i++){
5160             if(c2[i].getAttribute("_qdiff") != d){
5161                 r[r.length] = c2[i];
5162             }
5163         }
5164         for(var i = 0, len = c1.length; i < len; i++){
5165            c1[i].removeAttribute("_qdiff");
5166         }
5167         return r;
5168     }
5169
5170     function quickDiff(c1, c2){
5171         var len1 = c1.length;
5172         if(!len1){
5173             return c2;
5174         }
5175         if(isIE && c1[0].selectSingleNode){
5176             return quickDiffIEXml(c1, c2);
5177         }
5178         var d = ++key;
5179         for(var i = 0; i < len1; i++){
5180             c1[i]._qdiff = d;
5181         }
5182         var r = [];
5183         for(var i = 0, len = c2.length; i < len; i++){
5184             if(c2[i]._qdiff != d){
5185                 r[r.length] = c2[i];
5186             }
5187         }
5188         return r;
5189     }
5190
5191     function quickId(ns, mode, root, id){
5192         if(ns == root){
5193            var d = root.ownerDocument || root;
5194            return d.getElementById(id);
5195         }
5196         ns = getNodes(ns, mode, "*");
5197         return byId(ns, null, id);
5198     }
5199
5200     return {
5201         getStyle : function(el, name){
5202             return Roo.fly(el).getStyle(name);
5203         },
5204         /**
5205          * Compiles a selector/xpath query into a reusable function. The returned function
5206          * takes one parameter "root" (optional), which is the context node from where the query should start.
5207          * @param {String} selector The selector/xpath query
5208          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5209          * @return {Function}
5210          */
5211         compile : function(path, type){
5212             type = type || "select";
5213             
5214             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5215             var q = path, mode, lq;
5216             var tk = Roo.DomQuery.matchers;
5217             var tklen = tk.length;
5218             var mm;
5219
5220             // accept leading mode switch
5221             var lmode = q.match(modeRe);
5222             if(lmode && lmode[1]){
5223                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5224                 q = q.replace(lmode[1], "");
5225             }
5226             // strip leading slashes
5227             while(path.substr(0, 1)=="/"){
5228                 path = path.substr(1);
5229             }
5230
5231             while(q && lq != q){
5232                 lq = q;
5233                 var tm = q.match(tagTokenRe);
5234                 if(type == "select"){
5235                     if(tm){
5236                         if(tm[1] == "#"){
5237                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5238                         }else{
5239                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5240                         }
5241                         q = q.replace(tm[0], "");
5242                     }else if(q.substr(0, 1) != '@'){
5243                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5244                     }
5245                 }else{
5246                     if(tm){
5247                         if(tm[1] == "#"){
5248                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5249                         }else{
5250                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5251                         }
5252                         q = q.replace(tm[0], "");
5253                     }
5254                 }
5255                 while(!(mm = q.match(modeRe))){
5256                     var matched = false;
5257                     for(var j = 0; j < tklen; j++){
5258                         var t = tk[j];
5259                         var m = q.match(t.re);
5260                         if(m){
5261                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5262                                                     return m[i];
5263                                                 });
5264                             q = q.replace(m[0], "");
5265                             matched = true;
5266                             break;
5267                         }
5268                     }
5269                     // prevent infinite loop on bad selector
5270                     if(!matched){
5271                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5272                     }
5273                 }
5274                 if(mm[1]){
5275                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5276                     q = q.replace(mm[1], "");
5277                 }
5278             }
5279             fn[fn.length] = "return nodup(n);\n}";
5280             
5281              /** 
5282               * list of variables that need from compression as they are used by eval.
5283              *  eval:var:batch 
5284              *  eval:var:nodup
5285              *  eval:var:byTag
5286              *  eval:var:ById
5287              *  eval:var:getNodes
5288              *  eval:var:quickId
5289              *  eval:var:mode
5290              *  eval:var:root
5291              *  eval:var:n
5292              *  eval:var:byClassName
5293              *  eval:var:byPseudo
5294              *  eval:var:byAttribute
5295              *  eval:var:attrValue
5296              * 
5297              **/ 
5298             eval(fn.join(""));
5299             return f;
5300         },
5301
5302         /**
5303          * Selects a group of elements.
5304          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5305          * @param {Node} root (optional) The start of the query (defaults to document).
5306          * @return {Array}
5307          */
5308         select : function(path, root, type){
5309             if(!root || root == document){
5310                 root = document;
5311             }
5312             if(typeof root == "string"){
5313                 root = document.getElementById(root);
5314             }
5315             var paths = path.split(",");
5316             var results = [];
5317             for(var i = 0, len = paths.length; i < len; i++){
5318                 var p = paths[i].replace(trimRe, "");
5319                 if(!cache[p]){
5320                     cache[p] = Roo.DomQuery.compile(p);
5321                     if(!cache[p]){
5322                         throw p + " is not a valid selector";
5323                     }
5324                 }
5325                 var result = cache[p](root);
5326                 if(result && result != document){
5327                     results = results.concat(result);
5328                 }
5329             }
5330             if(paths.length > 1){
5331                 return nodup(results);
5332             }
5333             return results;
5334         },
5335
5336         /**
5337          * Selects a single element.
5338          * @param {String} selector The selector/xpath query
5339          * @param {Node} root (optional) The start of the query (defaults to document).
5340          * @return {Element}
5341          */
5342         selectNode : function(path, root){
5343             return Roo.DomQuery.select(path, root)[0];
5344         },
5345
5346         /**
5347          * Selects the value of a node, optionally replacing null with the defaultValue.
5348          * @param {String} selector The selector/xpath query
5349          * @param {Node} root (optional) The start of the query (defaults to document).
5350          * @param {String} defaultValue
5351          */
5352         selectValue : function(path, root, defaultValue){
5353             path = path.replace(trimRe, "");
5354             if(!valueCache[path]){
5355                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5356             }
5357             var n = valueCache[path](root);
5358             n = n[0] ? n[0] : n;
5359             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5360             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5361         },
5362
5363         /**
5364          * Selects the value of a node, parsing integers and floats.
5365          * @param {String} selector The selector/xpath query
5366          * @param {Node} root (optional) The start of the query (defaults to document).
5367          * @param {Number} defaultValue
5368          * @return {Number}
5369          */
5370         selectNumber : function(path, root, defaultValue){
5371             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5372             return parseFloat(v);
5373         },
5374
5375         /**
5376          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5377          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5378          * @param {String} selector The simple selector to test
5379          * @return {Boolean}
5380          */
5381         is : function(el, ss){
5382             if(typeof el == "string"){
5383                 el = document.getElementById(el);
5384             }
5385             var isArray = (el instanceof Array);
5386             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5387             return isArray ? (result.length == el.length) : (result.length > 0);
5388         },
5389
5390         /**
5391          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5392          * @param {Array} el An array of elements to filter
5393          * @param {String} selector The simple selector to test
5394          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5395          * the selector instead of the ones that match
5396          * @return {Array}
5397          */
5398         filter : function(els, ss, nonMatches){
5399             ss = ss.replace(trimRe, "");
5400             if(!simpleCache[ss]){
5401                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5402             }
5403             var result = simpleCache[ss](els);
5404             return nonMatches ? quickDiff(result, els) : result;
5405         },
5406
5407         /**
5408          * Collection of matching regular expressions and code snippets.
5409          */
5410         matchers : [{
5411                 re: /^\.([\w-]+)/,
5412                 select: 'n = byClassName(n, null, " {1} ");'
5413             }, {
5414                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5415                 select: 'n = byPseudo(n, "{1}", "{2}");'
5416             },{
5417                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5418                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5419             }, {
5420                 re: /^#([\w-]+)/,
5421                 select: 'n = byId(n, null, "{1}");'
5422             },{
5423                 re: /^@([\w-]+)/,
5424                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5425             }
5426         ],
5427
5428         /**
5429          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5430          * 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;.
5431          */
5432         operators : {
5433             "=" : function(a, v){
5434                 return a == v;
5435             },
5436             "!=" : function(a, v){
5437                 return a != v;
5438             },
5439             "^=" : function(a, v){
5440                 return a && a.substr(0, v.length) == v;
5441             },
5442             "$=" : function(a, v){
5443                 return a && a.substr(a.length-v.length) == v;
5444             },
5445             "*=" : function(a, v){
5446                 return a && a.indexOf(v) !== -1;
5447             },
5448             "%=" : function(a, v){
5449                 return (a % v) == 0;
5450             },
5451             "|=" : function(a, v){
5452                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5453             },
5454             "~=" : function(a, v){
5455                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5456             }
5457         },
5458
5459         /**
5460          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5461          * and the argument (if any) supplied in the selector.
5462          */
5463         pseudos : {
5464             "first-child" : function(c){
5465                 var r = [], ri = -1, n;
5466                 for(var i = 0, ci; ci = n = c[i]; i++){
5467                     while((n = n.previousSibling) && n.nodeType != 1);
5468                     if(!n){
5469                         r[++ri] = ci;
5470                     }
5471                 }
5472                 return r;
5473             },
5474
5475             "last-child" : function(c){
5476                 var r = [], ri = -1, n;
5477                 for(var i = 0, ci; ci = n = c[i]; i++){
5478                     while((n = n.nextSibling) && n.nodeType != 1);
5479                     if(!n){
5480                         r[++ri] = ci;
5481                     }
5482                 }
5483                 return r;
5484             },
5485
5486             "nth-child" : function(c, a) {
5487                 var r = [], ri = -1;
5488                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5489                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5490                 for(var i = 0, n; n = c[i]; i++){
5491                     var pn = n.parentNode;
5492                     if (batch != pn._batch) {
5493                         var j = 0;
5494                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5495                             if(cn.nodeType == 1){
5496                                cn.nodeIndex = ++j;
5497                             }
5498                         }
5499                         pn._batch = batch;
5500                     }
5501                     if (f == 1) {
5502                         if (l == 0 || n.nodeIndex == l){
5503                             r[++ri] = n;
5504                         }
5505                     } else if ((n.nodeIndex + l) % f == 0){
5506                         r[++ri] = n;
5507                     }
5508                 }
5509
5510                 return r;
5511             },
5512
5513             "only-child" : function(c){
5514                 var r = [], ri = -1;;
5515                 for(var i = 0, ci; ci = c[i]; i++){
5516                     if(!prev(ci) && !next(ci)){
5517                         r[++ri] = ci;
5518                     }
5519                 }
5520                 return r;
5521             },
5522
5523             "empty" : function(c){
5524                 var r = [], ri = -1;
5525                 for(var i = 0, ci; ci = c[i]; i++){
5526                     var cns = ci.childNodes, j = 0, cn, empty = true;
5527                     while(cn = cns[j]){
5528                         ++j;
5529                         if(cn.nodeType == 1 || cn.nodeType == 3){
5530                             empty = false;
5531                             break;
5532                         }
5533                     }
5534                     if(empty){
5535                         r[++ri] = ci;
5536                     }
5537                 }
5538                 return r;
5539             },
5540
5541             "contains" : function(c, v){
5542                 var r = [], ri = -1;
5543                 for(var i = 0, ci; ci = c[i]; i++){
5544                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5545                         r[++ri] = ci;
5546                     }
5547                 }
5548                 return r;
5549             },
5550
5551             "nodeValue" : function(c, v){
5552                 var r = [], ri = -1;
5553                 for(var i = 0, ci; ci = c[i]; i++){
5554                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5555                         r[++ri] = ci;
5556                     }
5557                 }
5558                 return r;
5559             },
5560
5561             "checked" : function(c){
5562                 var r = [], ri = -1;
5563                 for(var i = 0, ci; ci = c[i]; i++){
5564                     if(ci.checked == true){
5565                         r[++ri] = ci;
5566                     }
5567                 }
5568                 return r;
5569             },
5570
5571             "not" : function(c, ss){
5572                 return Roo.DomQuery.filter(c, ss, true);
5573             },
5574
5575             "odd" : function(c){
5576                 return this["nth-child"](c, "odd");
5577             },
5578
5579             "even" : function(c){
5580                 return this["nth-child"](c, "even");
5581             },
5582
5583             "nth" : function(c, a){
5584                 return c[a-1] || [];
5585             },
5586
5587             "first" : function(c){
5588                 return c[0] || [];
5589             },
5590
5591             "last" : function(c){
5592                 return c[c.length-1] || [];
5593             },
5594
5595             "has" : function(c, ss){
5596                 var s = Roo.DomQuery.select;
5597                 var r = [], ri = -1;
5598                 for(var i = 0, ci; ci = c[i]; i++){
5599                     if(s(ss, ci).length > 0){
5600                         r[++ri] = ci;
5601                     }
5602                 }
5603                 return r;
5604             },
5605
5606             "next" : function(c, ss){
5607                 var is = Roo.DomQuery.is;
5608                 var r = [], ri = -1;
5609                 for(var i = 0, ci; ci = c[i]; i++){
5610                     var n = next(ci);
5611                     if(n && is(n, ss)){
5612                         r[++ri] = ci;
5613                     }
5614                 }
5615                 return r;
5616             },
5617
5618             "prev" : function(c, ss){
5619                 var is = Roo.DomQuery.is;
5620                 var r = [], ri = -1;
5621                 for(var i = 0, ci; ci = c[i]; i++){
5622                     var n = prev(ci);
5623                     if(n && is(n, ss)){
5624                         r[++ri] = ci;
5625                     }
5626                 }
5627                 return r;
5628             }
5629         }
5630     };
5631 }();
5632
5633 /**
5634  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5635  * @param {String} path The selector/xpath query
5636  * @param {Node} root (optional) The start of the query (defaults to document).
5637  * @return {Array}
5638  * @member Roo
5639  * @method query
5640  */
5641 Roo.query = Roo.DomQuery.select;
5642 /*
5643  * Based on:
5644  * Ext JS Library 1.1.1
5645  * Copyright(c) 2006-2007, Ext JS, LLC.
5646  *
5647  * Originally Released Under LGPL - original licence link has changed is not relivant.
5648  *
5649  * Fork - LGPL
5650  * <script type="text/javascript">
5651  */
5652
5653 /**
5654  * @class Roo.util.Observable
5655  * Base class that provides a common interface for publishing events. Subclasses are expected to
5656  * to have a property "events" with all the events defined.<br>
5657  * For example:
5658  * <pre><code>
5659  Employee = function(name){
5660     this.name = name;
5661     this.addEvents({
5662         "fired" : true,
5663         "quit" : true
5664     });
5665  }
5666  Roo.extend(Employee, Roo.util.Observable);
5667 </code></pre>
5668  * @param {Object} config properties to use (incuding events / listeners)
5669  */
5670
5671 Roo.util.Observable = function(cfg){
5672     
5673     cfg = cfg|| {};
5674     this.addEvents(cfg.events || {});
5675     if (cfg.events) {
5676         delete cfg.events; // make sure
5677     }
5678      
5679     Roo.apply(this, cfg);
5680     
5681     if(this.listeners){
5682         this.on(this.listeners);
5683         delete this.listeners;
5684     }
5685 };
5686 Roo.util.Observable.prototype = {
5687     /** 
5688  * @cfg {Object} listeners  list of events and functions to call for this object, 
5689  * For example :
5690  * <pre><code>
5691     listeners :  { 
5692        'click' : function(e) {
5693            ..... 
5694         } ,
5695         .... 
5696     } 
5697   </code></pre>
5698  */
5699     
5700     
5701     /**
5702      * Fires the specified event with the passed parameters (minus the event name).
5703      * @param {String} eventName
5704      * @param {Object...} args Variable number of parameters are passed to handlers
5705      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5706      */
5707     fireEvent : function(){
5708         var ce = this.events[arguments[0].toLowerCase()];
5709         if(typeof ce == "object"){
5710             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5711         }else{
5712             return true;
5713         }
5714     },
5715
5716     // private
5717     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5718
5719     /**
5720      * Appends an event handler to this component
5721      * @param {String}   eventName The type of event to listen for
5722      * @param {Function} handler The method the event invokes
5723      * @param {Object}   scope (optional) The scope in which to execute the handler
5724      * function. The handler function's "this" context.
5725      * @param {Object}   options (optional) An object containing handler configuration
5726      * properties. This may contain any of the following properties:<ul>
5727      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5728      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5729      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5730      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5731      * by the specified number of milliseconds. If the event fires again within that time, the original
5732      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5733      * </ul><br>
5734      * <p>
5735      * <b>Combining Options</b><br>
5736      * Using the options argument, it is possible to combine different types of listeners:<br>
5737      * <br>
5738      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5739                 <pre><code>
5740                 el.on('click', this.onClick, this, {
5741                         single: true,
5742                 delay: 100,
5743                 forumId: 4
5744                 });
5745                 </code></pre>
5746      * <p>
5747      * <b>Attaching multiple handlers in 1 call</b><br>
5748      * The method also allows for a single argument to be passed which is a config object containing properties
5749      * which specify multiple handlers.
5750      * <pre><code>
5751                 el.on({
5752                         'click': {
5753                         fn: this.onClick,
5754                         scope: this,
5755                         delay: 100
5756                 }, 
5757                 'mouseover': {
5758                         fn: this.onMouseOver,
5759                         scope: this
5760                 },
5761                 'mouseout': {
5762                         fn: this.onMouseOut,
5763                         scope: this
5764                 }
5765                 });
5766                 </code></pre>
5767      * <p>
5768      * Or a shorthand syntax which passes the same scope object to all handlers:
5769         <pre><code>
5770                 el.on({
5771                         'click': this.onClick,
5772                 'mouseover': this.onMouseOver,
5773                 'mouseout': this.onMouseOut,
5774                 scope: this
5775                 });
5776                 </code></pre>
5777      */
5778     addListener : function(eventName, fn, scope, o){
5779         if(typeof eventName == "object"){
5780             o = eventName;
5781             for(var e in o){
5782                 if(this.filterOptRe.test(e)){
5783                     continue;
5784                 }
5785                 if(typeof o[e] == "function"){
5786                     // shared options
5787                     this.addListener(e, o[e], o.scope,  o);
5788                 }else{
5789                     // individual options
5790                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5791                 }
5792             }
5793             return;
5794         }
5795         o = (!o || typeof o == "boolean") ? {} : o;
5796         eventName = eventName.toLowerCase();
5797         var ce = this.events[eventName] || true;
5798         if(typeof ce == "boolean"){
5799             ce = new Roo.util.Event(this, eventName);
5800             this.events[eventName] = ce;
5801         }
5802         ce.addListener(fn, scope, o);
5803     },
5804
5805     /**
5806      * Removes a listener
5807      * @param {String}   eventName     The type of event to listen for
5808      * @param {Function} handler        The handler to remove
5809      * @param {Object}   scope  (optional) The scope (this object) for the handler
5810      */
5811     removeListener : function(eventName, fn, scope){
5812         var ce = this.events[eventName.toLowerCase()];
5813         if(typeof ce == "object"){
5814             ce.removeListener(fn, scope);
5815         }
5816     },
5817
5818     /**
5819      * Removes all listeners for this object
5820      */
5821     purgeListeners : function(){
5822         for(var evt in this.events){
5823             if(typeof this.events[evt] == "object"){
5824                  this.events[evt].clearListeners();
5825             }
5826         }
5827     },
5828
5829     relayEvents : function(o, events){
5830         var createHandler = function(ename){
5831             return function(){
5832                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5833             };
5834         };
5835         for(var i = 0, len = events.length; i < len; i++){
5836             var ename = events[i];
5837             if(!this.events[ename]){ this.events[ename] = true; };
5838             o.on(ename, createHandler(ename), this);
5839         }
5840     },
5841
5842     /**
5843      * Used to define events on this Observable
5844      * @param {Object} object The object with the events defined
5845      */
5846     addEvents : function(o){
5847         if(!this.events){
5848             this.events = {};
5849         }
5850         Roo.applyIf(this.events, o);
5851     },
5852
5853     /**
5854      * Checks to see if this object has any listeners for a specified event
5855      * @param {String} eventName The name of the event to check for
5856      * @return {Boolean} True if the event is being listened for, else false
5857      */
5858     hasListener : function(eventName){
5859         var e = this.events[eventName];
5860         return typeof e == "object" && e.listeners.length > 0;
5861     }
5862 };
5863 /**
5864  * Appends an event handler to this element (shorthand for addListener)
5865  * @param {String}   eventName     The type of event to listen for
5866  * @param {Function} handler        The method the event invokes
5867  * @param {Object}   scope (optional) The scope in which to execute the handler
5868  * function. The handler function's "this" context.
5869  * @param {Object}   options  (optional)
5870  * @method
5871  */
5872 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5873 /**
5874  * Removes a listener (shorthand for removeListener)
5875  * @param {String}   eventName     The type of event to listen for
5876  * @param {Function} handler        The handler to remove
5877  * @param {Object}   scope  (optional) The scope (this object) for the handler
5878  * @method
5879  */
5880 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5881
5882 /**
5883  * Starts capture on the specified Observable. All events will be passed
5884  * to the supplied function with the event name + standard signature of the event
5885  * <b>before</b> the event is fired. If the supplied function returns false,
5886  * the event will not fire.
5887  * @param {Observable} o The Observable to capture
5888  * @param {Function} fn The function to call
5889  * @param {Object} scope (optional) The scope (this object) for the fn
5890  * @static
5891  */
5892 Roo.util.Observable.capture = function(o, fn, scope){
5893     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5894 };
5895
5896 /**
5897  * Removes <b>all</b> added captures from the Observable.
5898  * @param {Observable} o The Observable to release
5899  * @static
5900  */
5901 Roo.util.Observable.releaseCapture = function(o){
5902     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5903 };
5904
5905 (function(){
5906
5907     var createBuffered = function(h, o, scope){
5908         var task = new Roo.util.DelayedTask();
5909         return function(){
5910             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5911         };
5912     };
5913
5914     var createSingle = function(h, e, fn, scope){
5915         return function(){
5916             e.removeListener(fn, scope);
5917             return h.apply(scope, arguments);
5918         };
5919     };
5920
5921     var createDelayed = function(h, o, scope){
5922         return function(){
5923             var args = Array.prototype.slice.call(arguments, 0);
5924             setTimeout(function(){
5925                 h.apply(scope, args);
5926             }, o.delay || 10);
5927         };
5928     };
5929
5930     Roo.util.Event = function(obj, name){
5931         this.name = name;
5932         this.obj = obj;
5933         this.listeners = [];
5934     };
5935
5936     Roo.util.Event.prototype = {
5937         addListener : function(fn, scope, options){
5938             var o = options || {};
5939             scope = scope || this.obj;
5940             if(!this.isListening(fn, scope)){
5941                 var l = {fn: fn, scope: scope, options: o};
5942                 var h = fn;
5943                 if(o.delay){
5944                     h = createDelayed(h, o, scope);
5945                 }
5946                 if(o.single){
5947                     h = createSingle(h, this, fn, scope);
5948                 }
5949                 if(o.buffer){
5950                     h = createBuffered(h, o, scope);
5951                 }
5952                 l.fireFn = h;
5953                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5954                     this.listeners.push(l);
5955                 }else{
5956                     this.listeners = this.listeners.slice(0);
5957                     this.listeners.push(l);
5958                 }
5959             }
5960         },
5961
5962         findListener : function(fn, scope){
5963             scope = scope || this.obj;
5964             var ls = this.listeners;
5965             for(var i = 0, len = ls.length; i < len; i++){
5966                 var l = ls[i];
5967                 if(l.fn == fn && l.scope == scope){
5968                     return i;
5969                 }
5970             }
5971             return -1;
5972         },
5973
5974         isListening : function(fn, scope){
5975             return this.findListener(fn, scope) != -1;
5976         },
5977
5978         removeListener : function(fn, scope){
5979             var index;
5980             if((index = this.findListener(fn, scope)) != -1){
5981                 if(!this.firing){
5982                     this.listeners.splice(index, 1);
5983                 }else{
5984                     this.listeners = this.listeners.slice(0);
5985                     this.listeners.splice(index, 1);
5986                 }
5987                 return true;
5988             }
5989             return false;
5990         },
5991
5992         clearListeners : function(){
5993             this.listeners = [];
5994         },
5995
5996         fire : function(){
5997             var ls = this.listeners, scope, len = ls.length;
5998             if(len > 0){
5999                 this.firing = true;
6000                 var args = Array.prototype.slice.call(arguments, 0);
6001                 for(var i = 0; i < len; i++){
6002                     var l = ls[i];
6003                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6004                         this.firing = false;
6005                         return false;
6006                     }
6007                 }
6008                 this.firing = false;
6009             }
6010             return true;
6011         }
6012     };
6013 })();/*
6014  * Based on:
6015  * Ext JS Library 1.1.1
6016  * Copyright(c) 2006-2007, Ext JS, LLC.
6017  *
6018  * Originally Released Under LGPL - original licence link has changed is not relivant.
6019  *
6020  * Fork - LGPL
6021  * <script type="text/javascript">
6022  */
6023
6024 /**
6025  * @class Roo.EventManager
6026  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6027  * several useful events directly.
6028  * See {@link Roo.EventObject} for more details on normalized event objects.
6029  * @singleton
6030  */
6031 Roo.EventManager = function(){
6032     var docReadyEvent, docReadyProcId, docReadyState = false;
6033     var resizeEvent, resizeTask, textEvent, textSize;
6034     var E = Roo.lib.Event;
6035     var D = Roo.lib.Dom;
6036
6037
6038     var fireDocReady = function(){
6039         if(!docReadyState){
6040             docReadyState = true;
6041             Roo.isReady = true;
6042             if(docReadyProcId){
6043                 clearInterval(docReadyProcId);
6044             }
6045             if(Roo.isGecko || Roo.isOpera) {
6046                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6047             }
6048             if(Roo.isIE){
6049                 var defer = document.getElementById("ie-deferred-loader");
6050                 if(defer){
6051                     defer.onreadystatechange = null;
6052                     defer.parentNode.removeChild(defer);
6053                 }
6054             }
6055             if(docReadyEvent){
6056                 docReadyEvent.fire();
6057                 docReadyEvent.clearListeners();
6058             }
6059         }
6060     };
6061     
6062     var initDocReady = function(){
6063         docReadyEvent = new Roo.util.Event();
6064         if(Roo.isGecko || Roo.isOpera) {
6065             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6066         }else if(Roo.isIE){
6067             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6068             var defer = document.getElementById("ie-deferred-loader");
6069             defer.onreadystatechange = function(){
6070                 if(this.readyState == "complete"){
6071                     fireDocReady();
6072                 }
6073             };
6074         }else if(Roo.isSafari){ 
6075             docReadyProcId = setInterval(function(){
6076                 var rs = document.readyState;
6077                 if(rs == "complete") {
6078                     fireDocReady();     
6079                  }
6080             }, 10);
6081         }
6082         // no matter what, make sure it fires on load
6083         E.on(window, "load", fireDocReady);
6084     };
6085
6086     var createBuffered = function(h, o){
6087         var task = new Roo.util.DelayedTask(h);
6088         return function(e){
6089             // create new event object impl so new events don't wipe out properties
6090             e = new Roo.EventObjectImpl(e);
6091             task.delay(o.buffer, h, null, [e]);
6092         };
6093     };
6094
6095     var createSingle = function(h, el, ename, fn){
6096         return function(e){
6097             Roo.EventManager.removeListener(el, ename, fn);
6098             h(e);
6099         };
6100     };
6101
6102     var createDelayed = function(h, o){
6103         return function(e){
6104             // create new event object impl so new events don't wipe out properties
6105             e = new Roo.EventObjectImpl(e);
6106             setTimeout(function(){
6107                 h(e);
6108             }, o.delay || 10);
6109         };
6110     };
6111
6112     var listen = function(element, ename, opt, fn, scope){
6113         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6114         fn = fn || o.fn; scope = scope || o.scope;
6115         var el = Roo.getDom(element);
6116         if(!el){
6117             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6118         }
6119         var h = function(e){
6120             e = Roo.EventObject.setEvent(e);
6121             var t;
6122             if(o.delegate){
6123                 t = e.getTarget(o.delegate, el);
6124                 if(!t){
6125                     return;
6126                 }
6127             }else{
6128                 t = e.target;
6129             }
6130             if(o.stopEvent === true){
6131                 e.stopEvent();
6132             }
6133             if(o.preventDefault === true){
6134                e.preventDefault();
6135             }
6136             if(o.stopPropagation === true){
6137                 e.stopPropagation();
6138             }
6139
6140             if(o.normalized === false){
6141                 e = e.browserEvent;
6142             }
6143
6144             fn.call(scope || el, e, t, o);
6145         };
6146         if(o.delay){
6147             h = createDelayed(h, o);
6148         }
6149         if(o.single){
6150             h = createSingle(h, el, ename, fn);
6151         }
6152         if(o.buffer){
6153             h = createBuffered(h, o);
6154         }
6155         fn._handlers = fn._handlers || [];
6156         fn._handlers.push([Roo.id(el), ename, h]);
6157
6158         E.on(el, ename, h);
6159         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6160             el.addEventListener("DOMMouseScroll", h, false);
6161             E.on(window, 'unload', function(){
6162                 el.removeEventListener("DOMMouseScroll", h, false);
6163             });
6164         }
6165         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6166             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6167         }
6168         return h;
6169     };
6170
6171     var stopListening = function(el, ename, fn){
6172         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6173         if(hds){
6174             for(var i = 0, len = hds.length; i < len; i++){
6175                 var h = hds[i];
6176                 if(h[0] == id && h[1] == ename){
6177                     hd = h[2];
6178                     hds.splice(i, 1);
6179                     break;
6180                 }
6181             }
6182         }
6183         E.un(el, ename, hd);
6184         el = Roo.getDom(el);
6185         if(ename == "mousewheel" && el.addEventListener){
6186             el.removeEventListener("DOMMouseScroll", hd, false);
6187         }
6188         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6189             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6190         }
6191     };
6192
6193     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6194     
6195     var pub = {
6196         
6197         
6198         /** 
6199          * Fix for doc tools
6200          * @scope Roo.EventManager
6201          */
6202         
6203         
6204         /** 
6205          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6206          * object with a Roo.EventObject
6207          * @param {Function} fn        The method the event invokes
6208          * @param {Object}   scope    An object that becomes the scope of the handler
6209          * @param {boolean}  override If true, the obj passed in becomes
6210          *                             the execution scope of the listener
6211          * @return {Function} The wrapped function
6212          * @deprecated
6213          */
6214         wrap : function(fn, scope, override){
6215             return function(e){
6216                 Roo.EventObject.setEvent(e);
6217                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6218             };
6219         },
6220         
6221         /**
6222      * Appends an event handler to an element (shorthand for addListener)
6223      * @param {String/HTMLElement}   element        The html element or id to assign the
6224      * @param {String}   eventName The type of event to listen for
6225      * @param {Function} handler The method the event invokes
6226      * @param {Object}   scope (optional) The scope in which to execute the handler
6227      * function. The handler function's "this" context.
6228      * @param {Object}   options (optional) An object containing handler configuration
6229      * properties. This may contain any of the following properties:<ul>
6230      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6231      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6232      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6233      * <li>preventDefault {Boolean} True to prevent the default action</li>
6234      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6235      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6236      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6237      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6238      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6239      * by the specified number of milliseconds. If the event fires again within that time, the original
6240      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6241      * </ul><br>
6242      * <p>
6243      * <b>Combining Options</b><br>
6244      * Using the options argument, it is possible to combine different types of listeners:<br>
6245      * <br>
6246      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6247      * Code:<pre><code>
6248 el.on('click', this.onClick, this, {
6249     single: true,
6250     delay: 100,
6251     stopEvent : true,
6252     forumId: 4
6253 });</code></pre>
6254      * <p>
6255      * <b>Attaching multiple handlers in 1 call</b><br>
6256       * The method also allows for a single argument to be passed which is a config object containing properties
6257      * which specify multiple handlers.
6258      * <p>
6259      * Code:<pre><code>
6260 el.on({
6261     'click' : {
6262         fn: this.onClick
6263         scope: this,
6264         delay: 100
6265     },
6266     'mouseover' : {
6267         fn: this.onMouseOver
6268         scope: this
6269     },
6270     'mouseout' : {
6271         fn: this.onMouseOut
6272         scope: this
6273     }
6274 });</code></pre>
6275      * <p>
6276      * Or a shorthand syntax:<br>
6277      * Code:<pre><code>
6278 el.on({
6279     'click' : this.onClick,
6280     'mouseover' : this.onMouseOver,
6281     'mouseout' : this.onMouseOut
6282     scope: this
6283 });</code></pre>
6284      */
6285         addListener : function(element, eventName, fn, scope, options){
6286             if(typeof eventName == "object"){
6287                 var o = eventName;
6288                 for(var e in o){
6289                     if(propRe.test(e)){
6290                         continue;
6291                     }
6292                     if(typeof o[e] == "function"){
6293                         // shared options
6294                         listen(element, e, o, o[e], o.scope);
6295                     }else{
6296                         // individual options
6297                         listen(element, e, o[e]);
6298                     }
6299                 }
6300                 return;
6301             }
6302             return listen(element, eventName, options, fn, scope);
6303         },
6304         
6305         /**
6306          * Removes an event handler
6307          *
6308          * @param {String/HTMLElement}   element        The id or html element to remove the 
6309          *                             event from
6310          * @param {String}   eventName     The type of event
6311          * @param {Function} fn
6312          * @return {Boolean} True if a listener was actually removed
6313          */
6314         removeListener : function(element, eventName, fn){
6315             return stopListening(element, eventName, fn);
6316         },
6317         
6318         /**
6319          * Fires when the document is ready (before onload and before images are loaded). Can be 
6320          * accessed shorthanded Roo.onReady().
6321          * @param {Function} fn        The method the event invokes
6322          * @param {Object}   scope    An  object that becomes the scope of the handler
6323          * @param {boolean}  options
6324          */
6325         onDocumentReady : function(fn, scope, options){
6326             if(docReadyState){ // if it already fired
6327                 docReadyEvent.addListener(fn, scope, options);
6328                 docReadyEvent.fire();
6329                 docReadyEvent.clearListeners();
6330                 return;
6331             }
6332             if(!docReadyEvent){
6333                 initDocReady();
6334             }
6335             docReadyEvent.addListener(fn, scope, options);
6336         },
6337         
6338         /**
6339          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6340          * @param {Function} fn        The method the event invokes
6341          * @param {Object}   scope    An object that becomes the scope of the handler
6342          * @param {boolean}  options
6343          */
6344         onWindowResize : function(fn, scope, options){
6345             if(!resizeEvent){
6346                 resizeEvent = new Roo.util.Event();
6347                 resizeTask = new Roo.util.DelayedTask(function(){
6348                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6349                 });
6350                 E.on(window, "resize", function(){
6351                     if(Roo.isIE){
6352                         resizeTask.delay(50);
6353                     }else{
6354                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6355                     }
6356                 });
6357             }
6358             resizeEvent.addListener(fn, scope, options);
6359         },
6360
6361         /**
6362          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6363          * @param {Function} fn        The method the event invokes
6364          * @param {Object}   scope    An object that becomes the scope of the handler
6365          * @param {boolean}  options
6366          */
6367         onTextResize : function(fn, scope, options){
6368             if(!textEvent){
6369                 textEvent = new Roo.util.Event();
6370                 var textEl = new Roo.Element(document.createElement('div'));
6371                 textEl.dom.className = 'x-text-resize';
6372                 textEl.dom.innerHTML = 'X';
6373                 textEl.appendTo(document.body);
6374                 textSize = textEl.dom.offsetHeight;
6375                 setInterval(function(){
6376                     if(textEl.dom.offsetHeight != textSize){
6377                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6378                     }
6379                 }, this.textResizeInterval);
6380             }
6381             textEvent.addListener(fn, scope, options);
6382         },
6383
6384         /**
6385          * Removes the passed window resize listener.
6386          * @param {Function} fn        The method the event invokes
6387          * @param {Object}   scope    The scope of handler
6388          */
6389         removeResizeListener : function(fn, scope){
6390             if(resizeEvent){
6391                 resizeEvent.removeListener(fn, scope);
6392             }
6393         },
6394
6395         // private
6396         fireResize : function(){
6397             if(resizeEvent){
6398                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6399             }   
6400         },
6401         /**
6402          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6403          */
6404         ieDeferSrc : false,
6405         /**
6406          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6407          */
6408         textResizeInterval : 50
6409     };
6410     
6411     /**
6412      * Fix for doc tools
6413      * @scopeAlias pub=Roo.EventManager
6414      */
6415     
6416      /**
6417      * Appends an event handler to an element (shorthand for addListener)
6418      * @param {String/HTMLElement}   element        The html element or id to assign the
6419      * @param {String}   eventName The type of event to listen for
6420      * @param {Function} handler The method the event invokes
6421      * @param {Object}   scope (optional) The scope in which to execute the handler
6422      * function. The handler function's "this" context.
6423      * @param {Object}   options (optional) An object containing handler configuration
6424      * properties. This may contain any of the following properties:<ul>
6425      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6426      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6427      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6428      * <li>preventDefault {Boolean} True to prevent the default action</li>
6429      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6430      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6431      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6432      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6433      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6434      * by the specified number of milliseconds. If the event fires again within that time, the original
6435      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6436      * </ul><br>
6437      * <p>
6438      * <b>Combining Options</b><br>
6439      * Using the options argument, it is possible to combine different types of listeners:<br>
6440      * <br>
6441      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6442      * Code:<pre><code>
6443 el.on('click', this.onClick, this, {
6444     single: true,
6445     delay: 100,
6446     stopEvent : true,
6447     forumId: 4
6448 });</code></pre>
6449      * <p>
6450      * <b>Attaching multiple handlers in 1 call</b><br>
6451       * The method also allows for a single argument to be passed which is a config object containing properties
6452      * which specify multiple handlers.
6453      * <p>
6454      * Code:<pre><code>
6455 el.on({
6456     'click' : {
6457         fn: this.onClick
6458         scope: this,
6459         delay: 100
6460     },
6461     'mouseover' : {
6462         fn: this.onMouseOver
6463         scope: this
6464     },
6465     'mouseout' : {
6466         fn: this.onMouseOut
6467         scope: this
6468     }
6469 });</code></pre>
6470      * <p>
6471      * Or a shorthand syntax:<br>
6472      * Code:<pre><code>
6473 el.on({
6474     'click' : this.onClick,
6475     'mouseover' : this.onMouseOver,
6476     'mouseout' : this.onMouseOut
6477     scope: this
6478 });</code></pre>
6479      */
6480     pub.on = pub.addListener;
6481     pub.un = pub.removeListener;
6482
6483     pub.stoppedMouseDownEvent = new Roo.util.Event();
6484     return pub;
6485 }();
6486 /**
6487   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6488   * @param {Function} fn        The method the event invokes
6489   * @param {Object}   scope    An  object that becomes the scope of the handler
6490   * @param {boolean}  override If true, the obj passed in becomes
6491   *                             the execution scope of the listener
6492   * @member Roo
6493   * @method onReady
6494  */
6495 Roo.onReady = Roo.EventManager.onDocumentReady;
6496
6497 Roo.onReady(function(){
6498     var bd = Roo.get(document.body);
6499     if(!bd){ return; }
6500
6501     var cls = [
6502             Roo.isIE ? "roo-ie"
6503             : Roo.isGecko ? "roo-gecko"
6504             : Roo.isOpera ? "roo-opera"
6505             : Roo.isSafari ? "roo-safari" : ""];
6506
6507     if(Roo.isMac){
6508         cls.push("roo-mac");
6509     }
6510     if(Roo.isLinux){
6511         cls.push("roo-linux");
6512     }
6513     if(Roo.isBorderBox){
6514         cls.push('roo-border-box');
6515     }
6516     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6517         var p = bd.dom.parentNode;
6518         if(p){
6519             p.className += ' roo-strict';
6520         }
6521     }
6522     bd.addClass(cls.join(' '));
6523 });
6524
6525 /**
6526  * @class Roo.EventObject
6527  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6528  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6529  * Example:
6530  * <pre><code>
6531  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6532     e.preventDefault();
6533     var target = e.getTarget();
6534     ...
6535  }
6536  var myDiv = Roo.get("myDiv");
6537  myDiv.on("click", handleClick);
6538  //or
6539  Roo.EventManager.on("myDiv", 'click', handleClick);
6540  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6541  </code></pre>
6542  * @singleton
6543  */
6544 Roo.EventObject = function(){
6545     
6546     var E = Roo.lib.Event;
6547     
6548     // safari keypress events for special keys return bad keycodes
6549     var safariKeys = {
6550         63234 : 37, // left
6551         63235 : 39, // right
6552         63232 : 38, // up
6553         63233 : 40, // down
6554         63276 : 33, // page up
6555         63277 : 34, // page down
6556         63272 : 46, // delete
6557         63273 : 36, // home
6558         63275 : 35  // end
6559     };
6560
6561     // normalize button clicks
6562     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6563                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6564
6565     Roo.EventObjectImpl = function(e){
6566         if(e){
6567             this.setEvent(e.browserEvent || e);
6568         }
6569     };
6570     Roo.EventObjectImpl.prototype = {
6571         /**
6572          * Used to fix doc tools.
6573          * @scope Roo.EventObject.prototype
6574          */
6575             
6576
6577         
6578         
6579         /** The normal browser event */
6580         browserEvent : null,
6581         /** The button pressed in a mouse event */
6582         button : -1,
6583         /** True if the shift key was down during the event */
6584         shiftKey : false,
6585         /** True if the control key was down during the event */
6586         ctrlKey : false,
6587         /** True if the alt key was down during the event */
6588         altKey : false,
6589
6590         /** Key constant 
6591         * @type Number */
6592         BACKSPACE : 8,
6593         /** Key constant 
6594         * @type Number */
6595         TAB : 9,
6596         /** Key constant 
6597         * @type Number */
6598         RETURN : 13,
6599         /** Key constant 
6600         * @type Number */
6601         ENTER : 13,
6602         /** Key constant 
6603         * @type Number */
6604         SHIFT : 16,
6605         /** Key constant 
6606         * @type Number */
6607         CONTROL : 17,
6608         /** Key constant 
6609         * @type Number */
6610         ESC : 27,
6611         /** Key constant 
6612         * @type Number */
6613         SPACE : 32,
6614         /** Key constant 
6615         * @type Number */
6616         PAGEUP : 33,
6617         /** Key constant 
6618         * @type Number */
6619         PAGEDOWN : 34,
6620         /** Key constant 
6621         * @type Number */
6622         END : 35,
6623         /** Key constant 
6624         * @type Number */
6625         HOME : 36,
6626         /** Key constant 
6627         * @type Number */
6628         LEFT : 37,
6629         /** Key constant 
6630         * @type Number */
6631         UP : 38,
6632         /** Key constant 
6633         * @type Number */
6634         RIGHT : 39,
6635         /** Key constant 
6636         * @type Number */
6637         DOWN : 40,
6638         /** Key constant 
6639         * @type Number */
6640         DELETE : 46,
6641         /** Key constant 
6642         * @type Number */
6643         F5 : 116,
6644
6645            /** @private */
6646         setEvent : function(e){
6647             if(e == this || (e && e.browserEvent)){ // already wrapped
6648                 return e;
6649             }
6650             this.browserEvent = e;
6651             if(e){
6652                 // normalize buttons
6653                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6654                 if(e.type == 'click' && this.button == -1){
6655                     this.button = 0;
6656                 }
6657                 this.type = e.type;
6658                 this.shiftKey = e.shiftKey;
6659                 // mac metaKey behaves like ctrlKey
6660                 this.ctrlKey = e.ctrlKey || e.metaKey;
6661                 this.altKey = e.altKey;
6662                 // in getKey these will be normalized for the mac
6663                 this.keyCode = e.keyCode;
6664                 // keyup warnings on firefox.
6665                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6666                 // cache the target for the delayed and or buffered events
6667                 this.target = E.getTarget(e);
6668                 // same for XY
6669                 this.xy = E.getXY(e);
6670             }else{
6671                 this.button = -1;
6672                 this.shiftKey = false;
6673                 this.ctrlKey = false;
6674                 this.altKey = false;
6675                 this.keyCode = 0;
6676                 this.charCode =0;
6677                 this.target = null;
6678                 this.xy = [0, 0];
6679             }
6680             return this;
6681         },
6682
6683         /**
6684          * Stop the event (preventDefault and stopPropagation)
6685          */
6686         stopEvent : function(){
6687             if(this.browserEvent){
6688                 if(this.browserEvent.type == 'mousedown'){
6689                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6690                 }
6691                 E.stopEvent(this.browserEvent);
6692             }
6693         },
6694
6695         /**
6696          * Prevents the browsers default handling of the event.
6697          */
6698         preventDefault : function(){
6699             if(this.browserEvent){
6700                 E.preventDefault(this.browserEvent);
6701             }
6702         },
6703
6704         /** @private */
6705         isNavKeyPress : function(){
6706             var k = this.keyCode;
6707             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6708             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6709         },
6710
6711         isSpecialKey : function(){
6712             var k = this.keyCode;
6713             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6714             (k == 16) || (k == 17) ||
6715             (k >= 18 && k <= 20) ||
6716             (k >= 33 && k <= 35) ||
6717             (k >= 36 && k <= 39) ||
6718             (k >= 44 && k <= 45);
6719         },
6720         /**
6721          * Cancels bubbling of the event.
6722          */
6723         stopPropagation : function(){
6724             if(this.browserEvent){
6725                 if(this.type == 'mousedown'){
6726                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6727                 }
6728                 E.stopPropagation(this.browserEvent);
6729             }
6730         },
6731
6732         /**
6733          * Gets the key code for the event.
6734          * @return {Number}
6735          */
6736         getCharCode : function(){
6737             return this.charCode || this.keyCode;
6738         },
6739
6740         /**
6741          * Returns a normalized keyCode for the event.
6742          * @return {Number} The key code
6743          */
6744         getKey : function(){
6745             var k = this.keyCode || this.charCode;
6746             return Roo.isSafari ? (safariKeys[k] || k) : k;
6747         },
6748
6749         /**
6750          * Gets the x coordinate of the event.
6751          * @return {Number}
6752          */
6753         getPageX : function(){
6754             return this.xy[0];
6755         },
6756
6757         /**
6758          * Gets the y coordinate of the event.
6759          * @return {Number}
6760          */
6761         getPageY : function(){
6762             return this.xy[1];
6763         },
6764
6765         /**
6766          * Gets the time of the event.
6767          * @return {Number}
6768          */
6769         getTime : function(){
6770             if(this.browserEvent){
6771                 return E.getTime(this.browserEvent);
6772             }
6773             return null;
6774         },
6775
6776         /**
6777          * Gets the page coordinates of the event.
6778          * @return {Array} The xy values like [x, y]
6779          */
6780         getXY : function(){
6781             return this.xy;
6782         },
6783
6784         /**
6785          * Gets the target for the event.
6786          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6787          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6788                 search as a number or element (defaults to 10 || document.body)
6789          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6790          * @return {HTMLelement}
6791          */
6792         getTarget : function(selector, maxDepth, returnEl){
6793             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6794         },
6795         /**
6796          * Gets the related target.
6797          * @return {HTMLElement}
6798          */
6799         getRelatedTarget : function(){
6800             if(this.browserEvent){
6801                 return E.getRelatedTarget(this.browserEvent);
6802             }
6803             return null;
6804         },
6805
6806         /**
6807          * Normalizes mouse wheel delta across browsers
6808          * @return {Number} The delta
6809          */
6810         getWheelDelta : function(){
6811             var e = this.browserEvent;
6812             var delta = 0;
6813             if(e.wheelDelta){ /* IE/Opera. */
6814                 delta = e.wheelDelta/120;
6815             }else if(e.detail){ /* Mozilla case. */
6816                 delta = -e.detail/3;
6817             }
6818             return delta;
6819         },
6820
6821         /**
6822          * Returns true if the control, meta, shift or alt key was pressed during this event.
6823          * @return {Boolean}
6824          */
6825         hasModifier : function(){
6826             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6827         },
6828
6829         /**
6830          * Returns true if the target of this event equals el or is a child of el
6831          * @param {String/HTMLElement/Element} el
6832          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6833          * @return {Boolean}
6834          */
6835         within : function(el, related){
6836             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6837             return t && Roo.fly(el).contains(t);
6838         },
6839
6840         getPoint : function(){
6841             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6842         }
6843     };
6844
6845     return new Roo.EventObjectImpl();
6846 }();
6847             
6848     /*
6849  * Based on:
6850  * Ext JS Library 1.1.1
6851  * Copyright(c) 2006-2007, Ext JS, LLC.
6852  *
6853  * Originally Released Under LGPL - original licence link has changed is not relivant.
6854  *
6855  * Fork - LGPL
6856  * <script type="text/javascript">
6857  */
6858
6859  
6860 // was in Composite Element!??!?!
6861  
6862 (function(){
6863     var D = Roo.lib.Dom;
6864     var E = Roo.lib.Event;
6865     var A = Roo.lib.Anim;
6866
6867     // local style camelizing for speed
6868     var propCache = {};
6869     var camelRe = /(-[a-z])/gi;
6870     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6871     var view = document.defaultView;
6872
6873 /**
6874  * @class Roo.Element
6875  * Represents an Element in the DOM.<br><br>
6876  * Usage:<br>
6877 <pre><code>
6878 var el = Roo.get("my-div");
6879
6880 // or with getEl
6881 var el = getEl("my-div");
6882
6883 // or with a DOM element
6884 var el = Roo.get(myDivElement);
6885 </code></pre>
6886  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6887  * each call instead of constructing a new one.<br><br>
6888  * <b>Animations</b><br />
6889  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6890  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6891 <pre>
6892 Option    Default   Description
6893 --------- --------  ---------------------------------------------
6894 duration  .35       The duration of the animation in seconds
6895 easing    easeOut   The YUI easing method
6896 callback  none      A function to execute when the anim completes
6897 scope     this      The scope (this) of the callback function
6898 </pre>
6899 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6900 * manipulate the animation. Here's an example:
6901 <pre><code>
6902 var el = Roo.get("my-div");
6903
6904 // no animation
6905 el.setWidth(100);
6906
6907 // default animation
6908 el.setWidth(100, true);
6909
6910 // animation with some options set
6911 el.setWidth(100, {
6912     duration: 1,
6913     callback: this.foo,
6914     scope: this
6915 });
6916
6917 // using the "anim" property to get the Anim object
6918 var opt = {
6919     duration: 1,
6920     callback: this.foo,
6921     scope: this
6922 };
6923 el.setWidth(100, opt);
6924 ...
6925 if(opt.anim.isAnimated()){
6926     opt.anim.stop();
6927 }
6928 </code></pre>
6929 * <b> Composite (Collections of) Elements</b><br />
6930  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6931  * @constructor Create a new Element directly.
6932  * @param {String/HTMLElement} element
6933  * @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).
6934  */
6935     Roo.Element = function(element, forceNew){
6936         var dom = typeof element == "string" ?
6937                 document.getElementById(element) : element;
6938         if(!dom){ // invalid id/element
6939             return null;
6940         }
6941         var id = dom.id;
6942         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6943             return Roo.Element.cache[id];
6944         }
6945
6946         /**
6947          * The DOM element
6948          * @type HTMLElement
6949          */
6950         this.dom = dom;
6951
6952         /**
6953          * The DOM element ID
6954          * @type String
6955          */
6956         this.id = id || Roo.id(dom);
6957     };
6958
6959     var El = Roo.Element;
6960
6961     El.prototype = {
6962         /**
6963          * The element's default display mode  (defaults to "")
6964          * @type String
6965          */
6966         originalDisplay : "",
6967
6968         visibilityMode : 1,
6969         /**
6970          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6971          * @type String
6972          */
6973         defaultUnit : "px",
6974         /**
6975          * Sets the element's visibility mode. When setVisible() is called it
6976          * will use this to determine whether to set the visibility or the display property.
6977          * @param visMode Element.VISIBILITY or Element.DISPLAY
6978          * @return {Roo.Element} this
6979          */
6980         setVisibilityMode : function(visMode){
6981             this.visibilityMode = visMode;
6982             return this;
6983         },
6984         /**
6985          * Convenience method for setVisibilityMode(Element.DISPLAY)
6986          * @param {String} display (optional) What to set display to when visible
6987          * @return {Roo.Element} this
6988          */
6989         enableDisplayMode : function(display){
6990             this.setVisibilityMode(El.DISPLAY);
6991             if(typeof display != "undefined") this.originalDisplay = display;
6992             return this;
6993         },
6994
6995         /**
6996          * 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)
6997          * @param {String} selector The simple selector to test
6998          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6999                 search as a number or element (defaults to 10 || document.body)
7000          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7001          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7002          */
7003         findParent : function(simpleSelector, maxDepth, returnEl){
7004             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7005             maxDepth = maxDepth || 50;
7006             if(typeof maxDepth != "number"){
7007                 stopEl = Roo.getDom(maxDepth);
7008                 maxDepth = 10;
7009             }
7010             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7011                 if(dq.is(p, simpleSelector)){
7012                     return returnEl ? Roo.get(p) : p;
7013                 }
7014                 depth++;
7015                 p = p.parentNode;
7016             }
7017             return null;
7018         },
7019
7020
7021         /**
7022          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7023          * @param {String} selector The simple selector to test
7024          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7025                 search as a number or element (defaults to 10 || document.body)
7026          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7027          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7028          */
7029         findParentNode : function(simpleSelector, maxDepth, returnEl){
7030             var p = Roo.fly(this.dom.parentNode, '_internal');
7031             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7032         },
7033
7034         /**
7035          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7036          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7037          * @param {String} selector The simple selector to test
7038          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7039                 search as a number or element (defaults to 10 || document.body)
7040          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7041          */
7042         up : function(simpleSelector, maxDepth){
7043             return this.findParentNode(simpleSelector, maxDepth, true);
7044         },
7045
7046
7047
7048         /**
7049          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7050          * @param {String} selector The simple selector to test
7051          * @return {Boolean} True if this element matches the selector, else false
7052          */
7053         is : function(simpleSelector){
7054             return Roo.DomQuery.is(this.dom, simpleSelector);
7055         },
7056
7057         /**
7058          * Perform animation on this element.
7059          * @param {Object} args The YUI animation control args
7060          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7061          * @param {Function} onComplete (optional) Function to call when animation completes
7062          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7063          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7064          * @return {Roo.Element} this
7065          */
7066         animate : function(args, duration, onComplete, easing, animType){
7067             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7068             return this;
7069         },
7070
7071         /*
7072          * @private Internal animation call
7073          */
7074         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7075             animType = animType || 'run';
7076             opt = opt || {};
7077             var anim = Roo.lib.Anim[animType](
7078                 this.dom, args,
7079                 (opt.duration || defaultDur) || .35,
7080                 (opt.easing || defaultEase) || 'easeOut',
7081                 function(){
7082                     Roo.callback(cb, this);
7083                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7084                 },
7085                 this
7086             );
7087             opt.anim = anim;
7088             return anim;
7089         },
7090
7091         // private legacy anim prep
7092         preanim : function(a, i){
7093             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7094         },
7095
7096         /**
7097          * Removes worthless text nodes
7098          * @param {Boolean} forceReclean (optional) By default the element
7099          * keeps track if it has been cleaned already so
7100          * you can call this over and over. However, if you update the element and
7101          * need to force a reclean, you can pass true.
7102          */
7103         clean : function(forceReclean){
7104             if(this.isCleaned && forceReclean !== true){
7105                 return this;
7106             }
7107             var ns = /\S/;
7108             var d = this.dom, n = d.firstChild, ni = -1;
7109             while(n){
7110                 var nx = n.nextSibling;
7111                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7112                     d.removeChild(n);
7113                 }else{
7114                     n.nodeIndex = ++ni;
7115                 }
7116                 n = nx;
7117             }
7118             this.isCleaned = true;
7119             return this;
7120         },
7121
7122         // private
7123         calcOffsetsTo : function(el){
7124             el = Roo.get(el);
7125             var d = el.dom;
7126             var restorePos = false;
7127             if(el.getStyle('position') == 'static'){
7128                 el.position('relative');
7129                 restorePos = true;
7130             }
7131             var x = 0, y =0;
7132             var op = this.dom;
7133             while(op && op != d && op.tagName != 'HTML'){
7134                 x+= op.offsetLeft;
7135                 y+= op.offsetTop;
7136                 op = op.offsetParent;
7137             }
7138             if(restorePos){
7139                 el.position('static');
7140             }
7141             return [x, y];
7142         },
7143
7144         /**
7145          * Scrolls this element into view within the passed container.
7146          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7147          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7148          * @return {Roo.Element} this
7149          */
7150         scrollIntoView : function(container, hscroll){
7151             var c = Roo.getDom(container) || document.body;
7152             var el = this.dom;
7153
7154             var o = this.calcOffsetsTo(c),
7155                 l = o[0],
7156                 t = o[1],
7157                 b = t+el.offsetHeight,
7158                 r = l+el.offsetWidth;
7159
7160             var ch = c.clientHeight;
7161             var ct = parseInt(c.scrollTop, 10);
7162             var cl = parseInt(c.scrollLeft, 10);
7163             var cb = ct + ch;
7164             var cr = cl + c.clientWidth;
7165
7166             if(t < ct){
7167                 c.scrollTop = t;
7168             }else if(b > cb){
7169                 c.scrollTop = b-ch;
7170             }
7171
7172             if(hscroll !== false){
7173                 if(l < cl){
7174                     c.scrollLeft = l;
7175                 }else if(r > cr){
7176                     c.scrollLeft = r-c.clientWidth;
7177                 }
7178             }
7179             return this;
7180         },
7181
7182         // private
7183         scrollChildIntoView : function(child, hscroll){
7184             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7185         },
7186
7187         /**
7188          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7189          * the new height may not be available immediately.
7190          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7191          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7192          * @param {Function} onComplete (optional) Function to call when animation completes
7193          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7194          * @return {Roo.Element} this
7195          */
7196         autoHeight : function(animate, duration, onComplete, easing){
7197             var oldHeight = this.getHeight();
7198             this.clip();
7199             this.setHeight(1); // force clipping
7200             setTimeout(function(){
7201                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7202                 if(!animate){
7203                     this.setHeight(height);
7204                     this.unclip();
7205                     if(typeof onComplete == "function"){
7206                         onComplete();
7207                     }
7208                 }else{
7209                     this.setHeight(oldHeight); // restore original height
7210                     this.setHeight(height, animate, duration, function(){
7211                         this.unclip();
7212                         if(typeof onComplete == "function") onComplete();
7213                     }.createDelegate(this), easing);
7214                 }
7215             }.createDelegate(this), 0);
7216             return this;
7217         },
7218
7219         /**
7220          * Returns true if this element is an ancestor of the passed element
7221          * @param {HTMLElement/String} el The element to check
7222          * @return {Boolean} True if this element is an ancestor of el, else false
7223          */
7224         contains : function(el){
7225             if(!el){return false;}
7226             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7227         },
7228
7229         /**
7230          * Checks whether the element is currently visible using both visibility and display properties.
7231          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7232          * @return {Boolean} True if the element is currently visible, else false
7233          */
7234         isVisible : function(deep) {
7235             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7236             if(deep !== true || !vis){
7237                 return vis;
7238             }
7239             var p = this.dom.parentNode;
7240             while(p && p.tagName.toLowerCase() != "body"){
7241                 if(!Roo.fly(p, '_isVisible').isVisible()){
7242                     return false;
7243                 }
7244                 p = p.parentNode;
7245             }
7246             return true;
7247         },
7248
7249         /**
7250          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7251          * @param {String} selector The CSS selector
7252          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7253          * @return {CompositeElement/CompositeElementLite} The composite element
7254          */
7255         select : function(selector, unique){
7256             return El.select(selector, unique, this.dom);
7257         },
7258
7259         /**
7260          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7261          * @param {String} selector The CSS selector
7262          * @return {Array} An array of the matched nodes
7263          */
7264         query : function(selector, unique){
7265             return Roo.DomQuery.select(selector, this.dom);
7266         },
7267
7268         /**
7269          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7270          * @param {String} selector The CSS selector
7271          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7272          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7273          */
7274         child : function(selector, returnDom){
7275             var n = Roo.DomQuery.selectNode(selector, this.dom);
7276             return returnDom ? n : Roo.get(n);
7277         },
7278
7279         /**
7280          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7281          * @param {String} selector The CSS selector
7282          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7283          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284          */
7285         down : function(selector, returnDom){
7286             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7287             return returnDom ? n : Roo.get(n);
7288         },
7289
7290         /**
7291          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7292          * @param {String} group The group the DD object is member of
7293          * @param {Object} config The DD config object
7294          * @param {Object} overrides An object containing methods to override/implement on the DD object
7295          * @return {Roo.dd.DD} The DD object
7296          */
7297         initDD : function(group, config, overrides){
7298             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7299             return Roo.apply(dd, overrides);
7300         },
7301
7302         /**
7303          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7304          * @param {String} group The group the DDProxy object is member of
7305          * @param {Object} config The DDProxy config object
7306          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7307          * @return {Roo.dd.DDProxy} The DDProxy object
7308          */
7309         initDDProxy : function(group, config, overrides){
7310             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7311             return Roo.apply(dd, overrides);
7312         },
7313
7314         /**
7315          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7316          * @param {String} group The group the DDTarget object is member of
7317          * @param {Object} config The DDTarget config object
7318          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7319          * @return {Roo.dd.DDTarget} The DDTarget object
7320          */
7321         initDDTarget : function(group, config, overrides){
7322             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7323             return Roo.apply(dd, overrides);
7324         },
7325
7326         /**
7327          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7328          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7329          * @param {Boolean} visible Whether the element is visible
7330          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7331          * @return {Roo.Element} this
7332          */
7333          setVisible : function(visible, animate){
7334             if(!animate || !A){
7335                 if(this.visibilityMode == El.DISPLAY){
7336                     this.setDisplayed(visible);
7337                 }else{
7338                     this.fixDisplay();
7339                     this.dom.style.visibility = visible ? "visible" : "hidden";
7340                 }
7341             }else{
7342                 // closure for composites
7343                 var dom = this.dom;
7344                 var visMode = this.visibilityMode;
7345                 if(visible){
7346                     this.setOpacity(.01);
7347                     this.setVisible(true);
7348                 }
7349                 this.anim({opacity: { to: (visible?1:0) }},
7350                       this.preanim(arguments, 1),
7351                       null, .35, 'easeIn', function(){
7352                          if(!visible){
7353                              if(visMode == El.DISPLAY){
7354                                  dom.style.display = "none";
7355                              }else{
7356                                  dom.style.visibility = "hidden";
7357                              }
7358                              Roo.get(dom).setOpacity(1);
7359                          }
7360                      });
7361             }
7362             return this;
7363         },
7364
7365         /**
7366          * Returns true if display is not "none"
7367          * @return {Boolean}
7368          */
7369         isDisplayed : function() {
7370             return this.getStyle("display") != "none";
7371         },
7372
7373         /**
7374          * Toggles the element's visibility or display, depending on visibility mode.
7375          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7376          * @return {Roo.Element} this
7377          */
7378         toggle : function(animate){
7379             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7380             return this;
7381         },
7382
7383         /**
7384          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7385          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7386          * @return {Roo.Element} this
7387          */
7388         setDisplayed : function(value) {
7389             if(typeof value == "boolean"){
7390                value = value ? this.originalDisplay : "none";
7391             }
7392             this.setStyle("display", value);
7393             return this;
7394         },
7395
7396         /**
7397          * Tries to focus the element. Any exceptions are caught and ignored.
7398          * @return {Roo.Element} this
7399          */
7400         focus : function() {
7401             try{
7402                 this.dom.focus();
7403             }catch(e){}
7404             return this;
7405         },
7406
7407         /**
7408          * Tries to blur the element. Any exceptions are caught and ignored.
7409          * @return {Roo.Element} this
7410          */
7411         blur : function() {
7412             try{
7413                 this.dom.blur();
7414             }catch(e){}
7415             return this;
7416         },
7417
7418         /**
7419          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7420          * @param {String/Array} className The CSS class to add, or an array of classes
7421          * @return {Roo.Element} this
7422          */
7423         addClass : function(className){
7424             if(className instanceof Array){
7425                 for(var i = 0, len = className.length; i < len; i++) {
7426                     this.addClass(className[i]);
7427                 }
7428             }else{
7429                 if(className && !this.hasClass(className)){
7430                     this.dom.className = this.dom.className + " " + className;
7431                 }
7432             }
7433             return this;
7434         },
7435
7436         /**
7437          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7438          * @param {String/Array} className The CSS class to add, or an array of classes
7439          * @return {Roo.Element} this
7440          */
7441         radioClass : function(className){
7442             var siblings = this.dom.parentNode.childNodes;
7443             for(var i = 0; i < siblings.length; i++) {
7444                 var s = siblings[i];
7445                 if(s.nodeType == 1){
7446                     Roo.get(s).removeClass(className);
7447                 }
7448             }
7449             this.addClass(className);
7450             return this;
7451         },
7452
7453         /**
7454          * Removes one or more CSS classes from the element.
7455          * @param {String/Array} className The CSS class to remove, or an array of classes
7456          * @return {Roo.Element} this
7457          */
7458         removeClass : function(className){
7459             if(!className || !this.dom.className){
7460                 return this;
7461             }
7462             if(className instanceof Array){
7463                 for(var i = 0, len = className.length; i < len; i++) {
7464                     this.removeClass(className[i]);
7465                 }
7466             }else{
7467                 if(this.hasClass(className)){
7468                     var re = this.classReCache[className];
7469                     if (!re) {
7470                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7471                        this.classReCache[className] = re;
7472                     }
7473                     this.dom.className =
7474                         this.dom.className.replace(re, " ");
7475                 }
7476             }
7477             return this;
7478         },
7479
7480         // private
7481         classReCache: {},
7482
7483         /**
7484          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7485          * @param {String} className The CSS class to toggle
7486          * @return {Roo.Element} this
7487          */
7488         toggleClass : function(className){
7489             if(this.hasClass(className)){
7490                 this.removeClass(className);
7491             }else{
7492                 this.addClass(className);
7493             }
7494             return this;
7495         },
7496
7497         /**
7498          * Checks if the specified CSS class exists on this element's DOM node.
7499          * @param {String} className The CSS class to check for
7500          * @return {Boolean} True if the class exists, else false
7501          */
7502         hasClass : function(className){
7503             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7504         },
7505
7506         /**
7507          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7508          * @param {String} oldClassName The CSS class to replace
7509          * @param {String} newClassName The replacement CSS class
7510          * @return {Roo.Element} this
7511          */
7512         replaceClass : function(oldClassName, newClassName){
7513             this.removeClass(oldClassName);
7514             this.addClass(newClassName);
7515             return this;
7516         },
7517
7518         /**
7519          * Returns an object with properties matching the styles requested.
7520          * For example, el.getStyles('color', 'font-size', 'width') might return
7521          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7522          * @param {String} style1 A style name
7523          * @param {String} style2 A style name
7524          * @param {String} etc.
7525          * @return {Object} The style object
7526          */
7527         getStyles : function(){
7528             var a = arguments, len = a.length, r = {};
7529             for(var i = 0; i < len; i++){
7530                 r[a[i]] = this.getStyle(a[i]);
7531             }
7532             return r;
7533         },
7534
7535         /**
7536          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7537          * @param {String} property The style property whose value is returned.
7538          * @return {String} The current value of the style property for this element.
7539          */
7540         getStyle : function(){
7541             return view && view.getComputedStyle ?
7542                 function(prop){
7543                     var el = this.dom, v, cs, camel;
7544                     if(prop == 'float'){
7545                         prop = "cssFloat";
7546                     }
7547                     if(el.style && (v = el.style[prop])){
7548                         return v;
7549                     }
7550                     if(cs = view.getComputedStyle(el, "")){
7551                         if(!(camel = propCache[prop])){
7552                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7553                         }
7554                         return cs[camel];
7555                     }
7556                     return null;
7557                 } :
7558                 function(prop){
7559                     var el = this.dom, v, cs, camel;
7560                     if(prop == 'opacity'){
7561                         if(typeof el.style.filter == 'string'){
7562                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7563                             if(m){
7564                                 var fv = parseFloat(m[1]);
7565                                 if(!isNaN(fv)){
7566                                     return fv ? fv / 100 : 0;
7567                                 }
7568                             }
7569                         }
7570                         return 1;
7571                     }else if(prop == 'float'){
7572                         prop = "styleFloat";
7573                     }
7574                     if(!(camel = propCache[prop])){
7575                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7576                     }
7577                     if(v = el.style[camel]){
7578                         return v;
7579                     }
7580                     if(cs = el.currentStyle){
7581                         return cs[camel];
7582                     }
7583                     return null;
7584                 };
7585         }(),
7586
7587         /**
7588          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7589          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7590          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7591          * @return {Roo.Element} this
7592          */
7593         setStyle : function(prop, value){
7594             if(typeof prop == "string"){
7595                 
7596                 if (prop == 'float') {
7597                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7598                     return this;
7599                 }
7600                 
7601                 var camel;
7602                 if(!(camel = propCache[prop])){
7603                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7604                 }
7605                 
7606                 if(camel == 'opacity') {
7607                     this.setOpacity(value);
7608                 }else{
7609                     this.dom.style[camel] = value;
7610                 }
7611             }else{
7612                 for(var style in prop){
7613                     if(typeof prop[style] != "function"){
7614                        this.setStyle(style, prop[style]);
7615                     }
7616                 }
7617             }
7618             return this;
7619         },
7620
7621         /**
7622          * More flexible version of {@link #setStyle} for setting style properties.
7623          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7624          * a function which returns such a specification.
7625          * @return {Roo.Element} this
7626          */
7627         applyStyles : function(style){
7628             Roo.DomHelper.applyStyles(this.dom, style);
7629             return this;
7630         },
7631
7632         /**
7633           * 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).
7634           * @return {Number} The X position of the element
7635           */
7636         getX : function(){
7637             return D.getX(this.dom);
7638         },
7639
7640         /**
7641           * 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).
7642           * @return {Number} The Y position of the element
7643           */
7644         getY : function(){
7645             return D.getY(this.dom);
7646         },
7647
7648         /**
7649           * 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).
7650           * @return {Array} The XY position of the element
7651           */
7652         getXY : function(){
7653             return D.getXY(this.dom);
7654         },
7655
7656         /**
7657          * 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).
7658          * @param {Number} The X position of the element
7659          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7660          * @return {Roo.Element} this
7661          */
7662         setX : function(x, animate){
7663             if(!animate || !A){
7664                 D.setX(this.dom, x);
7665             }else{
7666                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7667             }
7668             return this;
7669         },
7670
7671         /**
7672          * 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).
7673          * @param {Number} The Y position of the element
7674          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7675          * @return {Roo.Element} this
7676          */
7677         setY : function(y, animate){
7678             if(!animate || !A){
7679                 D.setY(this.dom, y);
7680             }else{
7681                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7682             }
7683             return this;
7684         },
7685
7686         /**
7687          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7688          * @param {String} left The left CSS property value
7689          * @return {Roo.Element} this
7690          */
7691         setLeft : function(left){
7692             this.setStyle("left", this.addUnits(left));
7693             return this;
7694         },
7695
7696         /**
7697          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7698          * @param {String} top The top CSS property value
7699          * @return {Roo.Element} this
7700          */
7701         setTop : function(top){
7702             this.setStyle("top", this.addUnits(top));
7703             return this;
7704         },
7705
7706         /**
7707          * Sets the element's CSS right style.
7708          * @param {String} right The right CSS property value
7709          * @return {Roo.Element} this
7710          */
7711         setRight : function(right){
7712             this.setStyle("right", this.addUnits(right));
7713             return this;
7714         },
7715
7716         /**
7717          * Sets the element's CSS bottom style.
7718          * @param {String} bottom The bottom CSS property value
7719          * @return {Roo.Element} this
7720          */
7721         setBottom : function(bottom){
7722             this.setStyle("bottom", this.addUnits(bottom));
7723             return this;
7724         },
7725
7726         /**
7727          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7728          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7729          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7730          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7731          * @return {Roo.Element} this
7732          */
7733         setXY : function(pos, animate){
7734             if(!animate || !A){
7735                 D.setXY(this.dom, pos);
7736             }else{
7737                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7738             }
7739             return this;
7740         },
7741
7742         /**
7743          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7744          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7745          * @param {Number} x X value for new position (coordinates are page-based)
7746          * @param {Number} y Y value for new position (coordinates are page-based)
7747          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7748          * @return {Roo.Element} this
7749          */
7750         setLocation : function(x, y, animate){
7751             this.setXY([x, y], this.preanim(arguments, 2));
7752             return this;
7753         },
7754
7755         /**
7756          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7757          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7758          * @param {Number} x X value for new position (coordinates are page-based)
7759          * @param {Number} y Y value for new position (coordinates are page-based)
7760          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7761          * @return {Roo.Element} this
7762          */
7763         moveTo : function(x, y, animate){
7764             this.setXY([x, y], this.preanim(arguments, 2));
7765             return this;
7766         },
7767
7768         /**
7769          * Returns the region of the given element.
7770          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7771          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7772          */
7773         getRegion : function(){
7774             return D.getRegion(this.dom);
7775         },
7776
7777         /**
7778          * Returns the offset height of the element
7779          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7780          * @return {Number} The element's height
7781          */
7782         getHeight : function(contentHeight){
7783             var h = this.dom.offsetHeight || 0;
7784             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7785         },
7786
7787         /**
7788          * Returns the offset width of the element
7789          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7790          * @return {Number} The element's width
7791          */
7792         getWidth : function(contentWidth){
7793             var w = this.dom.offsetWidth || 0;
7794             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7795         },
7796
7797         /**
7798          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7799          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7800          * if a height has not been set using CSS.
7801          * @return {Number}
7802          */
7803         getComputedHeight : function(){
7804             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7805             if(!h){
7806                 h = parseInt(this.getStyle('height'), 10) || 0;
7807                 if(!this.isBorderBox()){
7808                     h += this.getFrameWidth('tb');
7809                 }
7810             }
7811             return h;
7812         },
7813
7814         /**
7815          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7816          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7817          * if a width has not been set using CSS.
7818          * @return {Number}
7819          */
7820         getComputedWidth : function(){
7821             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7822             if(!w){
7823                 w = parseInt(this.getStyle('width'), 10) || 0;
7824                 if(!this.isBorderBox()){
7825                     w += this.getFrameWidth('lr');
7826                 }
7827             }
7828             return w;
7829         },
7830
7831         /**
7832          * Returns the size of the element.
7833          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7834          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7835          */
7836         getSize : function(contentSize){
7837             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7838         },
7839
7840         /**
7841          * Returns the width and height of the viewport.
7842          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7843          */
7844         getViewSize : function(){
7845             var d = this.dom, doc = document, aw = 0, ah = 0;
7846             if(d == doc || d == doc.body){
7847                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7848             }else{
7849                 return {
7850                     width : d.clientWidth,
7851                     height: d.clientHeight
7852                 };
7853             }
7854         },
7855
7856         /**
7857          * Returns the value of the "value" attribute
7858          * @param {Boolean} asNumber true to parse the value as a number
7859          * @return {String/Number}
7860          */
7861         getValue : function(asNumber){
7862             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7863         },
7864
7865         // private
7866         adjustWidth : function(width){
7867             if(typeof width == "number"){
7868                 if(this.autoBoxAdjust && !this.isBorderBox()){
7869                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7870                 }
7871                 if(width < 0){
7872                     width = 0;
7873                 }
7874             }
7875             return width;
7876         },
7877
7878         // private
7879         adjustHeight : function(height){
7880             if(typeof height == "number"){
7881                if(this.autoBoxAdjust && !this.isBorderBox()){
7882                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7883                }
7884                if(height < 0){
7885                    height = 0;
7886                }
7887             }
7888             return height;
7889         },
7890
7891         /**
7892          * Set the width of the element
7893          * @param {Number} width The new width
7894          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7895          * @return {Roo.Element} this
7896          */
7897         setWidth : function(width, animate){
7898             width = this.adjustWidth(width);
7899             if(!animate || !A){
7900                 this.dom.style.width = this.addUnits(width);
7901             }else{
7902                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7903             }
7904             return this;
7905         },
7906
7907         /**
7908          * Set the height of the element
7909          * @param {Number} height The new height
7910          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7911          * @return {Roo.Element} this
7912          */
7913          setHeight : function(height, animate){
7914             height = this.adjustHeight(height);
7915             if(!animate || !A){
7916                 this.dom.style.height = this.addUnits(height);
7917             }else{
7918                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7919             }
7920             return this;
7921         },
7922
7923         /**
7924          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7925          * @param {Number} width The new width
7926          * @param {Number} height The new height
7927          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7928          * @return {Roo.Element} this
7929          */
7930          setSize : function(width, height, animate){
7931             if(typeof width == "object"){ // in case of object from getSize()
7932                 height = width.height; width = width.width;
7933             }
7934             width = this.adjustWidth(width); height = this.adjustHeight(height);
7935             if(!animate || !A){
7936                 this.dom.style.width = this.addUnits(width);
7937                 this.dom.style.height = this.addUnits(height);
7938             }else{
7939                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7940             }
7941             return this;
7942         },
7943
7944         /**
7945          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7946          * @param {Number} x X value for new position (coordinates are page-based)
7947          * @param {Number} y Y value for new position (coordinates are page-based)
7948          * @param {Number} width The new width
7949          * @param {Number} height The new height
7950          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7951          * @return {Roo.Element} this
7952          */
7953         setBounds : function(x, y, width, height, animate){
7954             if(!animate || !A){
7955                 this.setSize(width, height);
7956                 this.setLocation(x, y);
7957             }else{
7958                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7959                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7960                               this.preanim(arguments, 4), 'motion');
7961             }
7962             return this;
7963         },
7964
7965         /**
7966          * 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.
7967          * @param {Roo.lib.Region} region The region to fill
7968          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7969          * @return {Roo.Element} this
7970          */
7971         setRegion : function(region, animate){
7972             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7973             return this;
7974         },
7975
7976         /**
7977          * Appends an event handler
7978          *
7979          * @param {String}   eventName     The type of event to append
7980          * @param {Function} fn        The method the event invokes
7981          * @param {Object} scope       (optional) The scope (this object) of the fn
7982          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7983          */
7984         addListener : function(eventName, fn, scope, options){
7985             if (this.dom) {
7986                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7987             }
7988         },
7989
7990         /**
7991          * Removes an event handler from this element
7992          * @param {String} eventName the type of event to remove
7993          * @param {Function} fn the method the event invokes
7994          * @return {Roo.Element} this
7995          */
7996         removeListener : function(eventName, fn){
7997             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7998             return this;
7999         },
8000
8001         /**
8002          * Removes all previous added listeners from this element
8003          * @return {Roo.Element} this
8004          */
8005         removeAllListeners : function(){
8006             E.purgeElement(this.dom);
8007             return this;
8008         },
8009
8010         relayEvent : function(eventName, observable){
8011             this.on(eventName, function(e){
8012                 observable.fireEvent(eventName, e);
8013             });
8014         },
8015
8016         /**
8017          * Set the opacity of the element
8018          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8019          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8020          * @return {Roo.Element} this
8021          */
8022          setOpacity : function(opacity, animate){
8023             if(!animate || !A){
8024                 var s = this.dom.style;
8025                 if(Roo.isIE){
8026                     s.zoom = 1;
8027                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8028                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8029                 }else{
8030                     s.opacity = opacity;
8031                 }
8032             }else{
8033                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8034             }
8035             return this;
8036         },
8037
8038         /**
8039          * Gets the left X coordinate
8040          * @param {Boolean} local True to get the local css position instead of page coordinate
8041          * @return {Number}
8042          */
8043         getLeft : function(local){
8044             if(!local){
8045                 return this.getX();
8046             }else{
8047                 return parseInt(this.getStyle("left"), 10) || 0;
8048             }
8049         },
8050
8051         /**
8052          * Gets the right X coordinate of the element (element X position + element width)
8053          * @param {Boolean} local True to get the local css position instead of page coordinate
8054          * @return {Number}
8055          */
8056         getRight : function(local){
8057             if(!local){
8058                 return this.getX() + this.getWidth();
8059             }else{
8060                 return (this.getLeft(true) + this.getWidth()) || 0;
8061             }
8062         },
8063
8064         /**
8065          * Gets the top Y coordinate
8066          * @param {Boolean} local True to get the local css position instead of page coordinate
8067          * @return {Number}
8068          */
8069         getTop : function(local) {
8070             if(!local){
8071                 return this.getY();
8072             }else{
8073                 return parseInt(this.getStyle("top"), 10) || 0;
8074             }
8075         },
8076
8077         /**
8078          * Gets the bottom Y coordinate of the element (element Y position + element height)
8079          * @param {Boolean} local True to get the local css position instead of page coordinate
8080          * @return {Number}
8081          */
8082         getBottom : function(local){
8083             if(!local){
8084                 return this.getY() + this.getHeight();
8085             }else{
8086                 return (this.getTop(true) + this.getHeight()) || 0;
8087             }
8088         },
8089
8090         /**
8091         * Initializes positioning on this element. If a desired position is not passed, it will make the
8092         * the element positioned relative IF it is not already positioned.
8093         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8094         * @param {Number} zIndex (optional) The zIndex to apply
8095         * @param {Number} x (optional) Set the page X position
8096         * @param {Number} y (optional) Set the page Y position
8097         */
8098         position : function(pos, zIndex, x, y){
8099             if(!pos){
8100                if(this.getStyle('position') == 'static'){
8101                    this.setStyle('position', 'relative');
8102                }
8103             }else{
8104                 this.setStyle("position", pos);
8105             }
8106             if(zIndex){
8107                 this.setStyle("z-index", zIndex);
8108             }
8109             if(x !== undefined && y !== undefined){
8110                 this.setXY([x, y]);
8111             }else if(x !== undefined){
8112                 this.setX(x);
8113             }else if(y !== undefined){
8114                 this.setY(y);
8115             }
8116         },
8117
8118         /**
8119         * Clear positioning back to the default when the document was loaded
8120         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8121         * @return {Roo.Element} this
8122          */
8123         clearPositioning : function(value){
8124             value = value ||'';
8125             this.setStyle({
8126                 "left": value,
8127                 "right": value,
8128                 "top": value,
8129                 "bottom": value,
8130                 "z-index": "",
8131                 "position" : "static"
8132             });
8133             return this;
8134         },
8135
8136         /**
8137         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8138         * snapshot before performing an update and then restoring the element.
8139         * @return {Object}
8140         */
8141         getPositioning : function(){
8142             var l = this.getStyle("left");
8143             var t = this.getStyle("top");
8144             return {
8145                 "position" : this.getStyle("position"),
8146                 "left" : l,
8147                 "right" : l ? "" : this.getStyle("right"),
8148                 "top" : t,
8149                 "bottom" : t ? "" : this.getStyle("bottom"),
8150                 "z-index" : this.getStyle("z-index")
8151             };
8152         },
8153
8154         /**
8155          * Gets the width of the border(s) for the specified side(s)
8156          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8157          * passing lr would get the border (l)eft width + the border (r)ight width.
8158          * @return {Number} The width of the sides passed added together
8159          */
8160         getBorderWidth : function(side){
8161             return this.addStyles(side, El.borders);
8162         },
8163
8164         /**
8165          * Gets the width of the padding(s) for the specified side(s)
8166          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167          * passing lr would get the padding (l)eft + the padding (r)ight.
8168          * @return {Number} The padding of the sides passed added together
8169          */
8170         getPadding : function(side){
8171             return this.addStyles(side, El.paddings);
8172         },
8173
8174         /**
8175         * Set positioning with an object returned by getPositioning().
8176         * @param {Object} posCfg
8177         * @return {Roo.Element} this
8178          */
8179         setPositioning : function(pc){
8180             this.applyStyles(pc);
8181             if(pc.right == "auto"){
8182                 this.dom.style.right = "";
8183             }
8184             if(pc.bottom == "auto"){
8185                 this.dom.style.bottom = "";
8186             }
8187             return this;
8188         },
8189
8190         // private
8191         fixDisplay : function(){
8192             if(this.getStyle("display") == "none"){
8193                 this.setStyle("visibility", "hidden");
8194                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8195                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8196                     this.setStyle("display", "block");
8197                 }
8198             }
8199         },
8200
8201         /**
8202          * Quick set left and top adding default units
8203          * @param {String} left The left CSS property value
8204          * @param {String} top The top CSS property value
8205          * @return {Roo.Element} this
8206          */
8207          setLeftTop : function(left, top){
8208             this.dom.style.left = this.addUnits(left);
8209             this.dom.style.top = this.addUnits(top);
8210             return this;
8211         },
8212
8213         /**
8214          * Move this element relative to its current position.
8215          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8216          * @param {Number} distance How far to move the element in pixels
8217          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8218          * @return {Roo.Element} this
8219          */
8220          move : function(direction, distance, animate){
8221             var xy = this.getXY();
8222             direction = direction.toLowerCase();
8223             switch(direction){
8224                 case "l":
8225                 case "left":
8226                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8227                     break;
8228                case "r":
8229                case "right":
8230                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8231                     break;
8232                case "t":
8233                case "top":
8234                case "up":
8235                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8236                     break;
8237                case "b":
8238                case "bottom":
8239                case "down":
8240                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8241                     break;
8242             }
8243             return this;
8244         },
8245
8246         /**
8247          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8248          * @return {Roo.Element} this
8249          */
8250         clip : function(){
8251             if(!this.isClipped){
8252                this.isClipped = true;
8253                this.originalClip = {
8254                    "o": this.getStyle("overflow"),
8255                    "x": this.getStyle("overflow-x"),
8256                    "y": this.getStyle("overflow-y")
8257                };
8258                this.setStyle("overflow", "hidden");
8259                this.setStyle("overflow-x", "hidden");
8260                this.setStyle("overflow-y", "hidden");
8261             }
8262             return this;
8263         },
8264
8265         /**
8266          *  Return clipping (overflow) to original clipping before clip() was called
8267          * @return {Roo.Element} this
8268          */
8269         unclip : function(){
8270             if(this.isClipped){
8271                 this.isClipped = false;
8272                 var o = this.originalClip;
8273                 if(o.o){this.setStyle("overflow", o.o);}
8274                 if(o.x){this.setStyle("overflow-x", o.x);}
8275                 if(o.y){this.setStyle("overflow-y", o.y);}
8276             }
8277             return this;
8278         },
8279
8280
8281         /**
8282          * Gets the x,y coordinates specified by the anchor position on the element.
8283          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8284          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8285          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8286          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8287          * @return {Array} [x, y] An array containing the element's x and y coordinates
8288          */
8289         getAnchorXY : function(anchor, local, s){
8290             //Passing a different size is useful for pre-calculating anchors,
8291             //especially for anchored animations that change the el size.
8292
8293             var w, h, vp = false;
8294             if(!s){
8295                 var d = this.dom;
8296                 if(d == document.body || d == document){
8297                     vp = true;
8298                     w = D.getViewWidth(); h = D.getViewHeight();
8299                 }else{
8300                     w = this.getWidth(); h = this.getHeight();
8301                 }
8302             }else{
8303                 w = s.width;  h = s.height;
8304             }
8305             var x = 0, y = 0, r = Math.round;
8306             switch((anchor || "tl").toLowerCase()){
8307                 case "c":
8308                     x = r(w*.5);
8309                     y = r(h*.5);
8310                 break;
8311                 case "t":
8312                     x = r(w*.5);
8313                     y = 0;
8314                 break;
8315                 case "l":
8316                     x = 0;
8317                     y = r(h*.5);
8318                 break;
8319                 case "r":
8320                     x = w;
8321                     y = r(h*.5);
8322                 break;
8323                 case "b":
8324                     x = r(w*.5);
8325                     y = h;
8326                 break;
8327                 case "tl":
8328                     x = 0;
8329                     y = 0;
8330                 break;
8331                 case "bl":
8332                     x = 0;
8333                     y = h;
8334                 break;
8335                 case "br":
8336                     x = w;
8337                     y = h;
8338                 break;
8339                 case "tr":
8340                     x = w;
8341                     y = 0;
8342                 break;
8343             }
8344             if(local === true){
8345                 return [x, y];
8346             }
8347             if(vp){
8348                 var sc = this.getScroll();
8349                 return [x + sc.left, y + sc.top];
8350             }
8351             //Add the element's offset xy
8352             var o = this.getXY();
8353             return [x+o[0], y+o[1]];
8354         },
8355
8356         /**
8357          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8358          * supported position values.
8359          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8360          * @param {String} position The position to align to.
8361          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8362          * @return {Array} [x, y]
8363          */
8364         getAlignToXY : function(el, p, o){
8365             el = Roo.get(el);
8366             var d = this.dom;
8367             if(!el.dom){
8368                 throw "Element.alignTo with an element that doesn't exist";
8369             }
8370             var c = false; //constrain to viewport
8371             var p1 = "", p2 = "";
8372             o = o || [0,0];
8373
8374             if(!p){
8375                 p = "tl-bl";
8376             }else if(p == "?"){
8377                 p = "tl-bl?";
8378             }else if(p.indexOf("-") == -1){
8379                 p = "tl-" + p;
8380             }
8381             p = p.toLowerCase();
8382             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8383             if(!m){
8384                throw "Element.alignTo with an invalid alignment " + p;
8385             }
8386             p1 = m[1]; p2 = m[2]; c = !!m[3];
8387
8388             //Subtract the aligned el's internal xy from the target's offset xy
8389             //plus custom offset to get the aligned el's new offset xy
8390             var a1 = this.getAnchorXY(p1, true);
8391             var a2 = el.getAnchorXY(p2, false);
8392             var x = a2[0] - a1[0] + o[0];
8393             var y = a2[1] - a1[1] + o[1];
8394             if(c){
8395                 //constrain the aligned el to viewport if necessary
8396                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8397                 // 5px of margin for ie
8398                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8399
8400                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8401                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8402                 //otherwise swap the aligned el to the opposite border of the target.
8403                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8404                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8405                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8406                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8407
8408                var doc = document;
8409                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8410                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8411
8412                if((x+w) > dw + scrollX){
8413                     x = swapX ? r.left-w : dw+scrollX-w;
8414                 }
8415                if(x < scrollX){
8416                    x = swapX ? r.right : scrollX;
8417                }
8418                if((y+h) > dh + scrollY){
8419                     y = swapY ? r.top-h : dh+scrollY-h;
8420                 }
8421                if (y < scrollY){
8422                    y = swapY ? r.bottom : scrollY;
8423                }
8424             }
8425             return [x,y];
8426         },
8427
8428         // private
8429         getConstrainToXY : function(){
8430             var os = {top:0, left:0, bottom:0, right: 0};
8431
8432             return function(el, local, offsets, proposedXY){
8433                 el = Roo.get(el);
8434                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8435
8436                 var vw, vh, vx = 0, vy = 0;
8437                 if(el.dom == document.body || el.dom == document){
8438                     vw = Roo.lib.Dom.getViewWidth();
8439                     vh = Roo.lib.Dom.getViewHeight();
8440                 }else{
8441                     vw = el.dom.clientWidth;
8442                     vh = el.dom.clientHeight;
8443                     if(!local){
8444                         var vxy = el.getXY();
8445                         vx = vxy[0];
8446                         vy = vxy[1];
8447                     }
8448                 }
8449
8450                 var s = el.getScroll();
8451
8452                 vx += offsets.left + s.left;
8453                 vy += offsets.top + s.top;
8454
8455                 vw -= offsets.right;
8456                 vh -= offsets.bottom;
8457
8458                 var vr = vx+vw;
8459                 var vb = vy+vh;
8460
8461                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8462                 var x = xy[0], y = xy[1];
8463                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8464
8465                 // only move it if it needs it
8466                 var moved = false;
8467
8468                 // first validate right/bottom
8469                 if((x + w) > vr){
8470                     x = vr - w;
8471                     moved = true;
8472                 }
8473                 if((y + h) > vb){
8474                     y = vb - h;
8475                     moved = true;
8476                 }
8477                 // then make sure top/left isn't negative
8478                 if(x < vx){
8479                     x = vx;
8480                     moved = true;
8481                 }
8482                 if(y < vy){
8483                     y = vy;
8484                     moved = true;
8485                 }
8486                 return moved ? [x, y] : false;
8487             };
8488         }(),
8489
8490         // private
8491         adjustForConstraints : function(xy, parent, offsets){
8492             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8493         },
8494
8495         /**
8496          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8497          * document it aligns it to the viewport.
8498          * The position parameter is optional, and can be specified in any one of the following formats:
8499          * <ul>
8500          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8501          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8502          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8503          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8504          *   <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
8505          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8506          * </ul>
8507          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8508          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8509          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8510          * that specified in order to enforce the viewport constraints.
8511          * Following are all of the supported anchor positions:
8512     <pre>
8513     Value  Description
8514     -----  -----------------------------
8515     tl     The top left corner (default)
8516     t      The center of the top edge
8517     tr     The top right corner
8518     l      The center of the left edge
8519     c      In the center of the element
8520     r      The center of the right edge
8521     bl     The bottom left corner
8522     b      The center of the bottom edge
8523     br     The bottom right corner
8524     </pre>
8525     Example Usage:
8526     <pre><code>
8527     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8528     el.alignTo("other-el");
8529
8530     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8531     el.alignTo("other-el", "tr?");
8532
8533     // align the bottom right corner of el with the center left edge of other-el
8534     el.alignTo("other-el", "br-l?");
8535
8536     // align the center of el with the bottom left corner of other-el and
8537     // adjust the x position by -6 pixels (and the y position by 0)
8538     el.alignTo("other-el", "c-bl", [-6, 0]);
8539     </code></pre>
8540          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8541          * @param {String} position The position to align to.
8542          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8543          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8544          * @return {Roo.Element} this
8545          */
8546         alignTo : function(element, position, offsets, animate){
8547             var xy = this.getAlignToXY(element, position, offsets);
8548             this.setXY(xy, this.preanim(arguments, 3));
8549             return this;
8550         },
8551
8552         /**
8553          * Anchors an element to another element and realigns it when the window is resized.
8554          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8555          * @param {String} position The position to align to.
8556          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8557          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8558          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8559          * is a number, it is used as the buffer delay (defaults to 50ms).
8560          * @param {Function} callback The function to call after the animation finishes
8561          * @return {Roo.Element} this
8562          */
8563         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8564             var action = function(){
8565                 this.alignTo(el, alignment, offsets, animate);
8566                 Roo.callback(callback, this);
8567             };
8568             Roo.EventManager.onWindowResize(action, this);
8569             var tm = typeof monitorScroll;
8570             if(tm != 'undefined'){
8571                 Roo.EventManager.on(window, 'scroll', action, this,
8572                     {buffer: tm == 'number' ? monitorScroll : 50});
8573             }
8574             action.call(this); // align immediately
8575             return this;
8576         },
8577         /**
8578          * Clears any opacity settings from this element. Required in some cases for IE.
8579          * @return {Roo.Element} this
8580          */
8581         clearOpacity : function(){
8582             if (window.ActiveXObject) {
8583                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8584                     this.dom.style.filter = "";
8585                 }
8586             } else {
8587                 this.dom.style.opacity = "";
8588                 this.dom.style["-moz-opacity"] = "";
8589                 this.dom.style["-khtml-opacity"] = "";
8590             }
8591             return this;
8592         },
8593
8594         /**
8595          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8596          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8597          * @return {Roo.Element} this
8598          */
8599         hide : function(animate){
8600             this.setVisible(false, this.preanim(arguments, 0));
8601             return this;
8602         },
8603
8604         /**
8605         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607          * @return {Roo.Element} this
8608          */
8609         show : function(animate){
8610             this.setVisible(true, this.preanim(arguments, 0));
8611             return this;
8612         },
8613
8614         /**
8615          * @private Test if size has a unit, otherwise appends the default
8616          */
8617         addUnits : function(size){
8618             return Roo.Element.addUnits(size, this.defaultUnit);
8619         },
8620
8621         /**
8622          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8623          * @return {Roo.Element} this
8624          */
8625         beginMeasure : function(){
8626             var el = this.dom;
8627             if(el.offsetWidth || el.offsetHeight){
8628                 return this; // offsets work already
8629             }
8630             var changed = [];
8631             var p = this.dom, b = document.body; // start with this element
8632             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8633                 var pe = Roo.get(p);
8634                 if(pe.getStyle('display') == 'none'){
8635                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8636                     p.style.visibility = "hidden";
8637                     p.style.display = "block";
8638                 }
8639                 p = p.parentNode;
8640             }
8641             this._measureChanged = changed;
8642             return this;
8643
8644         },
8645
8646         /**
8647          * Restores displays to before beginMeasure was called
8648          * @return {Roo.Element} this
8649          */
8650         endMeasure : function(){
8651             var changed = this._measureChanged;
8652             if(changed){
8653                 for(var i = 0, len = changed.length; i < len; i++) {
8654                     var r = changed[i];
8655                     r.el.style.visibility = r.visibility;
8656                     r.el.style.display = "none";
8657                 }
8658                 this._measureChanged = null;
8659             }
8660             return this;
8661         },
8662
8663         /**
8664         * Update the innerHTML of this element, optionally searching for and processing scripts
8665         * @param {String} html The new HTML
8666         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8667         * @param {Function} callback For async script loading you can be noticed when the update completes
8668         * @return {Roo.Element} this
8669          */
8670         update : function(html, loadScripts, callback){
8671             if(typeof html == "undefined"){
8672                 html = "";
8673             }
8674             if(loadScripts !== true){
8675                 this.dom.innerHTML = html;
8676                 if(typeof callback == "function"){
8677                     callback();
8678                 }
8679                 return this;
8680             }
8681             var id = Roo.id();
8682             var dom = this.dom;
8683
8684             html += '<span id="' + id + '"></span>';
8685
8686             E.onAvailable(id, function(){
8687                 var hd = document.getElementsByTagName("head")[0];
8688                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8689                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8690                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8691
8692                 var match;
8693                 while(match = re.exec(html)){
8694                     var attrs = match[1];
8695                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8696                     if(srcMatch && srcMatch[2]){
8697                        var s = document.createElement("script");
8698                        s.src = srcMatch[2];
8699                        var typeMatch = attrs.match(typeRe);
8700                        if(typeMatch && typeMatch[2]){
8701                            s.type = typeMatch[2];
8702                        }
8703                        hd.appendChild(s);
8704                     }else if(match[2] && match[2].length > 0){
8705                         if(window.execScript) {
8706                            window.execScript(match[2]);
8707                         } else {
8708                             /**
8709                              * eval:var:id
8710                              * eval:var:dom
8711                              * eval:var:html
8712                              * 
8713                              */
8714                            window.eval(match[2]);
8715                         }
8716                     }
8717                 }
8718                 var el = document.getElementById(id);
8719                 if(el){el.parentNode.removeChild(el);}
8720                 if(typeof callback == "function"){
8721                     callback();
8722                 }
8723             });
8724             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8725             return this;
8726         },
8727
8728         /**
8729          * Direct access to the UpdateManager update() method (takes the same parameters).
8730          * @param {String/Function} url The url for this request or a function to call to get the url
8731          * @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}
8732          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8733          * @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.
8734          * @return {Roo.Element} this
8735          */
8736         load : function(){
8737             var um = this.getUpdateManager();
8738             um.update.apply(um, arguments);
8739             return this;
8740         },
8741
8742         /**
8743         * Gets this element's UpdateManager
8744         * @return {Roo.UpdateManager} The UpdateManager
8745         */
8746         getUpdateManager : function(){
8747             if(!this.updateManager){
8748                 this.updateManager = new Roo.UpdateManager(this);
8749             }
8750             return this.updateManager;
8751         },
8752
8753         /**
8754          * Disables text selection for this element (normalized across browsers)
8755          * @return {Roo.Element} this
8756          */
8757         unselectable : function(){
8758             this.dom.unselectable = "on";
8759             this.swallowEvent("selectstart", true);
8760             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8761             this.addClass("x-unselectable");
8762             return this;
8763         },
8764
8765         /**
8766         * Calculates the x, y to center this element on the screen
8767         * @return {Array} The x, y values [x, y]
8768         */
8769         getCenterXY : function(){
8770             return this.getAlignToXY(document, 'c-c');
8771         },
8772
8773         /**
8774         * Centers the Element in either the viewport, or another Element.
8775         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8776         */
8777         center : function(centerIn){
8778             this.alignTo(centerIn || document, 'c-c');
8779             return this;
8780         },
8781
8782         /**
8783          * Tests various css rules/browsers to determine if this element uses a border box
8784          * @return {Boolean}
8785          */
8786         isBorderBox : function(){
8787             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8788         },
8789
8790         /**
8791          * Return a box {x, y, width, height} that can be used to set another elements
8792          * size/location to match this element.
8793          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8794          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8795          * @return {Object} box An object in the format {x, y, width, height}
8796          */
8797         getBox : function(contentBox, local){
8798             var xy;
8799             if(!local){
8800                 xy = this.getXY();
8801             }else{
8802                 var left = parseInt(this.getStyle("left"), 10) || 0;
8803                 var top = parseInt(this.getStyle("top"), 10) || 0;
8804                 xy = [left, top];
8805             }
8806             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8807             if(!contentBox){
8808                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8809             }else{
8810                 var l = this.getBorderWidth("l")+this.getPadding("l");
8811                 var r = this.getBorderWidth("r")+this.getPadding("r");
8812                 var t = this.getBorderWidth("t")+this.getPadding("t");
8813                 var b = this.getBorderWidth("b")+this.getPadding("b");
8814                 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)};
8815             }
8816             bx.right = bx.x + bx.width;
8817             bx.bottom = bx.y + bx.height;
8818             return bx;
8819         },
8820
8821         /**
8822          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8823          for more information about the sides.
8824          * @param {String} sides
8825          * @return {Number}
8826          */
8827         getFrameWidth : function(sides, onlyContentBox){
8828             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8829         },
8830
8831         /**
8832          * 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.
8833          * @param {Object} box The box to fill {x, y, width, height}
8834          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8835          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8836          * @return {Roo.Element} this
8837          */
8838         setBox : function(box, adjust, animate){
8839             var w = box.width, h = box.height;
8840             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8841                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8842                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8843             }
8844             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8845             return this;
8846         },
8847
8848         /**
8849          * Forces the browser to repaint this element
8850          * @return {Roo.Element} this
8851          */
8852          repaint : function(){
8853             var dom = this.dom;
8854             this.addClass("x-repaint");
8855             setTimeout(function(){
8856                 Roo.get(dom).removeClass("x-repaint");
8857             }, 1);
8858             return this;
8859         },
8860
8861         /**
8862          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8863          * then it returns the calculated width of the sides (see getPadding)
8864          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8865          * @return {Object/Number}
8866          */
8867         getMargins : function(side){
8868             if(!side){
8869                 return {
8870                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8871                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8872                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8873                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8874                 };
8875             }else{
8876                 return this.addStyles(side, El.margins);
8877              }
8878         },
8879
8880         // private
8881         addStyles : function(sides, styles){
8882             var val = 0, v, w;
8883             for(var i = 0, len = sides.length; i < len; i++){
8884                 v = this.getStyle(styles[sides.charAt(i)]);
8885                 if(v){
8886                      w = parseInt(v, 10);
8887                      if(w){ val += w; }
8888                 }
8889             }
8890             return val;
8891         },
8892
8893         /**
8894          * Creates a proxy element of this element
8895          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8896          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8897          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8898          * @return {Roo.Element} The new proxy element
8899          */
8900         createProxy : function(config, renderTo, matchBox){
8901             if(renderTo){
8902                 renderTo = Roo.getDom(renderTo);
8903             }else{
8904                 renderTo = document.body;
8905             }
8906             config = typeof config == "object" ?
8907                 config : {tag : "div", cls: config};
8908             var proxy = Roo.DomHelper.append(renderTo, config, true);
8909             if(matchBox){
8910                proxy.setBox(this.getBox());
8911             }
8912             return proxy;
8913         },
8914
8915         /**
8916          * Puts a mask over this element to disable user interaction. Requires core.css.
8917          * This method can only be applied to elements which accept child nodes.
8918          * @param {String} msg (optional) A message to display in the mask
8919          * @param {String} msgCls (optional) A css class to apply to the msg element
8920          * @return {Element} The mask  element
8921          */
8922         mask : function(msg, msgCls)
8923         {
8924             if(this.getStyle("position") == "static"){
8925                 this.setStyle("position", "relative");
8926             }
8927             if(!this._mask){
8928                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8929             }
8930             this.addClass("x-masked");
8931             this._mask.setDisplayed(true);
8932             
8933             // we wander
8934             var z = 0;
8935             var dom = this.dom
8936             while (dom && dom.style) {
8937                 if (!isNaN(parseInt(dom.style.zIndex))) {
8938                     z = Math.max(z, parseInt(dom.style.zIndex));
8939                 }
8940                 dom = dom.parentNode;
8941             }
8942             // if we are masking the body - then it hides everything..
8943             if (this.dom == document.body) {
8944                 z = 1000000;
8945                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8946                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8947             }
8948            
8949             if(typeof msg == 'string'){
8950                 if(!this._maskMsg){
8951                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8952                 }
8953                 var mm = this._maskMsg;
8954                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8955                 mm.dom.firstChild.innerHTML = msg;
8956                 mm.setDisplayed(true);
8957                 mm.center(this);
8958                 mm.setStyle('z-index', z + 102);
8959             }
8960             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8961                 this._mask.setHeight(this.getHeight());
8962             }
8963             this._mask.setStyle('z-index', z + 100);
8964             
8965             return this._mask;
8966         },
8967
8968         /**
8969          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8970          * it is cached for reuse.
8971          */
8972         unmask : function(removeEl){
8973             if(this._mask){
8974                 if(removeEl === true){
8975                     this._mask.remove();
8976                     delete this._mask;
8977                     if(this._maskMsg){
8978                         this._maskMsg.remove();
8979                         delete this._maskMsg;
8980                     }
8981                 }else{
8982                     this._mask.setDisplayed(false);
8983                     if(this._maskMsg){
8984                         this._maskMsg.setDisplayed(false);
8985                     }
8986                 }
8987             }
8988             this.removeClass("x-masked");
8989         },
8990
8991         /**
8992          * Returns true if this element is masked
8993          * @return {Boolean}
8994          */
8995         isMasked : function(){
8996             return this._mask && this._mask.isVisible();
8997         },
8998
8999         /**
9000          * Creates an iframe shim for this element to keep selects and other windowed objects from
9001          * showing through.
9002          * @return {Roo.Element} The new shim element
9003          */
9004         createShim : function(){
9005             var el = document.createElement('iframe');
9006             el.frameBorder = 'no';
9007             el.className = 'roo-shim';
9008             if(Roo.isIE && Roo.isSecure){
9009                 el.src = Roo.SSL_SECURE_URL;
9010             }
9011             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9012             shim.autoBoxAdjust = false;
9013             return shim;
9014         },
9015
9016         /**
9017          * Removes this element from the DOM and deletes it from the cache
9018          */
9019         remove : function(){
9020             if(this.dom.parentNode){
9021                 this.dom.parentNode.removeChild(this.dom);
9022             }
9023             delete El.cache[this.dom.id];
9024         },
9025
9026         /**
9027          * Sets up event handlers to add and remove a css class when the mouse is over this element
9028          * @param {String} className
9029          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9030          * mouseout events for children elements
9031          * @return {Roo.Element} this
9032          */
9033         addClassOnOver : function(className, preventFlicker){
9034             this.on("mouseover", function(){
9035                 Roo.fly(this, '_internal').addClass(className);
9036             }, this.dom);
9037             var removeFn = function(e){
9038                 if(preventFlicker !== true || !e.within(this, true)){
9039                     Roo.fly(this, '_internal').removeClass(className);
9040                 }
9041             };
9042             this.on("mouseout", removeFn, this.dom);
9043             return this;
9044         },
9045
9046         /**
9047          * Sets up event handlers to add and remove a css class when this element has the focus
9048          * @param {String} className
9049          * @return {Roo.Element} this
9050          */
9051         addClassOnFocus : function(className){
9052             this.on("focus", function(){
9053                 Roo.fly(this, '_internal').addClass(className);
9054             }, this.dom);
9055             this.on("blur", function(){
9056                 Roo.fly(this, '_internal').removeClass(className);
9057             }, this.dom);
9058             return this;
9059         },
9060         /**
9061          * 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)
9062          * @param {String} className
9063          * @return {Roo.Element} this
9064          */
9065         addClassOnClick : function(className){
9066             var dom = this.dom;
9067             this.on("mousedown", function(){
9068                 Roo.fly(dom, '_internal').addClass(className);
9069                 var d = Roo.get(document);
9070                 var fn = function(){
9071                     Roo.fly(dom, '_internal').removeClass(className);
9072                     d.removeListener("mouseup", fn);
9073                 };
9074                 d.on("mouseup", fn);
9075             });
9076             return this;
9077         },
9078
9079         /**
9080          * Stops the specified event from bubbling and optionally prevents the default action
9081          * @param {String} eventName
9082          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9083          * @return {Roo.Element} this
9084          */
9085         swallowEvent : function(eventName, preventDefault){
9086             var fn = function(e){
9087                 e.stopPropagation();
9088                 if(preventDefault){
9089                     e.preventDefault();
9090                 }
9091             };
9092             if(eventName instanceof Array){
9093                 for(var i = 0, len = eventName.length; i < len; i++){
9094                      this.on(eventName[i], fn);
9095                 }
9096                 return this;
9097             }
9098             this.on(eventName, fn);
9099             return this;
9100         },
9101
9102         /**
9103          * @private
9104          */
9105       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9106
9107         /**
9108          * Sizes this element to its parent element's dimensions performing
9109          * neccessary box adjustments.
9110          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9111          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9112          * @return {Roo.Element} this
9113          */
9114         fitToParent : function(monitorResize, targetParent) {
9115           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9116           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9117           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9118             return;
9119           }
9120           var p = Roo.get(targetParent || this.dom.parentNode);
9121           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9122           if (monitorResize === true) {
9123             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9124             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9125           }
9126           return this;
9127         },
9128
9129         /**
9130          * Gets the next sibling, skipping text nodes
9131          * @return {HTMLElement} The next sibling or null
9132          */
9133         getNextSibling : function(){
9134             var n = this.dom.nextSibling;
9135             while(n && n.nodeType != 1){
9136                 n = n.nextSibling;
9137             }
9138             return n;
9139         },
9140
9141         /**
9142          * Gets the previous sibling, skipping text nodes
9143          * @return {HTMLElement} The previous sibling or null
9144          */
9145         getPrevSibling : function(){
9146             var n = this.dom.previousSibling;
9147             while(n && n.nodeType != 1){
9148                 n = n.previousSibling;
9149             }
9150             return n;
9151         },
9152
9153
9154         /**
9155          * Appends the passed element(s) to this element
9156          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9157          * @return {Roo.Element} this
9158          */
9159         appendChild: function(el){
9160             el = Roo.get(el);
9161             el.appendTo(this);
9162             return this;
9163         },
9164
9165         /**
9166          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9167          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9168          * automatically generated with the specified attributes.
9169          * @param {HTMLElement} insertBefore (optional) a child element of this element
9170          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9171          * @return {Roo.Element} The new child element
9172          */
9173         createChild: function(config, insertBefore, returnDom){
9174             config = config || {tag:'div'};
9175             if(insertBefore){
9176                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9177             }
9178             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9179         },
9180
9181         /**
9182          * Appends this element to the passed element
9183          * @param {String/HTMLElement/Element} el The new parent element
9184          * @return {Roo.Element} this
9185          */
9186         appendTo: function(el){
9187             el = Roo.getDom(el);
9188             el.appendChild(this.dom);
9189             return this;
9190         },
9191
9192         /**
9193          * Inserts this element before the passed element in the DOM
9194          * @param {String/HTMLElement/Element} el The element to insert before
9195          * @return {Roo.Element} this
9196          */
9197         insertBefore: function(el){
9198             el = Roo.getDom(el);
9199             el.parentNode.insertBefore(this.dom, el);
9200             return this;
9201         },
9202
9203         /**
9204          * Inserts this element after the passed element in the DOM
9205          * @param {String/HTMLElement/Element} el The element to insert after
9206          * @return {Roo.Element} this
9207          */
9208         insertAfter: function(el){
9209             el = Roo.getDom(el);
9210             el.parentNode.insertBefore(this.dom, el.nextSibling);
9211             return this;
9212         },
9213
9214         /**
9215          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9216          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9217          * @return {Roo.Element} The new child
9218          */
9219         insertFirst: function(el, returnDom){
9220             el = el || {};
9221             if(typeof el == 'object' && !el.nodeType){ // dh config
9222                 return this.createChild(el, this.dom.firstChild, returnDom);
9223             }else{
9224                 el = Roo.getDom(el);
9225                 this.dom.insertBefore(el, this.dom.firstChild);
9226                 return !returnDom ? Roo.get(el) : el;
9227             }
9228         },
9229
9230         /**
9231          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9232          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9233          * @param {String} where (optional) 'before' or 'after' defaults to before
9234          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9235          * @return {Roo.Element} the inserted Element
9236          */
9237         insertSibling: function(el, where, returnDom){
9238             where = where ? where.toLowerCase() : 'before';
9239             el = el || {};
9240             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9241
9242             if(typeof el == 'object' && !el.nodeType){ // dh config
9243                 if(where == 'after' && !this.dom.nextSibling){
9244                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9245                 }else{
9246                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9247                 }
9248
9249             }else{
9250                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9251                             where == 'before' ? this.dom : this.dom.nextSibling);
9252                 if(!returnDom){
9253                     rt = Roo.get(rt);
9254                 }
9255             }
9256             return rt;
9257         },
9258
9259         /**
9260          * Creates and wraps this element with another element
9261          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9262          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9263          * @return {HTMLElement/Element} The newly created wrapper element
9264          */
9265         wrap: function(config, returnDom){
9266             if(!config){
9267                 config = {tag: "div"};
9268             }
9269             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9270             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9271             return newEl;
9272         },
9273
9274         /**
9275          * Replaces the passed element with this element
9276          * @param {String/HTMLElement/Element} el The element to replace
9277          * @return {Roo.Element} this
9278          */
9279         replace: function(el){
9280             el = Roo.get(el);
9281             this.insertBefore(el);
9282             el.remove();
9283             return this;
9284         },
9285
9286         /**
9287          * Inserts an html fragment into this element
9288          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9289          * @param {String} html The HTML fragment
9290          * @param {Boolean} returnEl True to return an Roo.Element
9291          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9292          */
9293         insertHtml : function(where, html, returnEl){
9294             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9295             return returnEl ? Roo.get(el) : el;
9296         },
9297
9298         /**
9299          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9300          * @param {Object} o The object with the attributes
9301          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9302          * @return {Roo.Element} this
9303          */
9304         set : function(o, useSet){
9305             var el = this.dom;
9306             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9307             for(var attr in o){
9308                 if(attr == "style" || typeof o[attr] == "function") continue;
9309                 if(attr=="cls"){
9310                     el.className = o["cls"];
9311                 }else{
9312                     if(useSet) el.setAttribute(attr, o[attr]);
9313                     else el[attr] = o[attr];
9314                 }
9315             }
9316             if(o.style){
9317                 Roo.DomHelper.applyStyles(el, o.style);
9318             }
9319             return this;
9320         },
9321
9322         /**
9323          * Convenience method for constructing a KeyMap
9324          * @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:
9325          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9326          * @param {Function} fn The function to call
9327          * @param {Object} scope (optional) The scope of the function
9328          * @return {Roo.KeyMap} The KeyMap created
9329          */
9330         addKeyListener : function(key, fn, scope){
9331             var config;
9332             if(typeof key != "object" || key instanceof Array){
9333                 config = {
9334                     key: key,
9335                     fn: fn,
9336                     scope: scope
9337                 };
9338             }else{
9339                 config = {
9340                     key : key.key,
9341                     shift : key.shift,
9342                     ctrl : key.ctrl,
9343                     alt : key.alt,
9344                     fn: fn,
9345                     scope: scope
9346                 };
9347             }
9348             return new Roo.KeyMap(this, config);
9349         },
9350
9351         /**
9352          * Creates a KeyMap for this element
9353          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9354          * @return {Roo.KeyMap} The KeyMap created
9355          */
9356         addKeyMap : function(config){
9357             return new Roo.KeyMap(this, config);
9358         },
9359
9360         /**
9361          * Returns true if this element is scrollable.
9362          * @return {Boolean}
9363          */
9364          isScrollable : function(){
9365             var dom = this.dom;
9366             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9367         },
9368
9369         /**
9370          * 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().
9371          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9372          * @param {Number} value The new scroll value
9373          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9374          * @return {Element} this
9375          */
9376
9377         scrollTo : function(side, value, animate){
9378             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9379             if(!animate || !A){
9380                 this.dom[prop] = value;
9381             }else{
9382                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9383                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9384             }
9385             return this;
9386         },
9387
9388         /**
9389          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9390          * within this element's scrollable range.
9391          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9392          * @param {Number} distance How far to scroll the element in pixels
9393          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9394          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9395          * was scrolled as far as it could go.
9396          */
9397          scroll : function(direction, distance, animate){
9398              if(!this.isScrollable()){
9399                  return;
9400              }
9401              var el = this.dom;
9402              var l = el.scrollLeft, t = el.scrollTop;
9403              var w = el.scrollWidth, h = el.scrollHeight;
9404              var cw = el.clientWidth, ch = el.clientHeight;
9405              direction = direction.toLowerCase();
9406              var scrolled = false;
9407              var a = this.preanim(arguments, 2);
9408              switch(direction){
9409                  case "l":
9410                  case "left":
9411                      if(w - l > cw){
9412                          var v = Math.min(l + distance, w-cw);
9413                          this.scrollTo("left", v, a);
9414                          scrolled = true;
9415                      }
9416                      break;
9417                 case "r":
9418                 case "right":
9419                      if(l > 0){
9420                          var v = Math.max(l - distance, 0);
9421                          this.scrollTo("left", v, a);
9422                          scrolled = true;
9423                      }
9424                      break;
9425                 case "t":
9426                 case "top":
9427                 case "up":
9428                      if(t > 0){
9429                          var v = Math.max(t - distance, 0);
9430                          this.scrollTo("top", v, a);
9431                          scrolled = true;
9432                      }
9433                      break;
9434                 case "b":
9435                 case "bottom":
9436                 case "down":
9437                      if(h - t > ch){
9438                          var v = Math.min(t + distance, h-ch);
9439                          this.scrollTo("top", v, a);
9440                          scrolled = true;
9441                      }
9442                      break;
9443              }
9444              return scrolled;
9445         },
9446
9447         /**
9448          * Translates the passed page coordinates into left/top css values for this element
9449          * @param {Number/Array} x The page x or an array containing [x, y]
9450          * @param {Number} y The page y
9451          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9452          */
9453         translatePoints : function(x, y){
9454             if(typeof x == 'object' || x instanceof Array){
9455                 y = x[1]; x = x[0];
9456             }
9457             var p = this.getStyle('position');
9458             var o = this.getXY();
9459
9460             var l = parseInt(this.getStyle('left'), 10);
9461             var t = parseInt(this.getStyle('top'), 10);
9462
9463             if(isNaN(l)){
9464                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9465             }
9466             if(isNaN(t)){
9467                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9468             }
9469
9470             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9471         },
9472
9473         /**
9474          * Returns the current scroll position of the element.
9475          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9476          */
9477         getScroll : function(){
9478             var d = this.dom, doc = document;
9479             if(d == doc || d == doc.body){
9480                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9481                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9482                 return {left: l, top: t};
9483             }else{
9484                 return {left: d.scrollLeft, top: d.scrollTop};
9485             }
9486         },
9487
9488         /**
9489          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9490          * are convert to standard 6 digit hex color.
9491          * @param {String} attr The css attribute
9492          * @param {String} defaultValue The default value to use when a valid color isn't found
9493          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9494          * YUI color anims.
9495          */
9496         getColor : function(attr, defaultValue, prefix){
9497             var v = this.getStyle(attr);
9498             if(!v || v == "transparent" || v == "inherit") {
9499                 return defaultValue;
9500             }
9501             var color = typeof prefix == "undefined" ? "#" : prefix;
9502             if(v.substr(0, 4) == "rgb("){
9503                 var rvs = v.slice(4, v.length -1).split(",");
9504                 for(var i = 0; i < 3; i++){
9505                     var h = parseInt(rvs[i]).toString(16);
9506                     if(h < 16){
9507                         h = "0" + h;
9508                     }
9509                     color += h;
9510                 }
9511             } else {
9512                 if(v.substr(0, 1) == "#"){
9513                     if(v.length == 4) {
9514                         for(var i = 1; i < 4; i++){
9515                             var c = v.charAt(i);
9516                             color +=  c + c;
9517                         }
9518                     }else if(v.length == 7){
9519                         color += v.substr(1);
9520                     }
9521                 }
9522             }
9523             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9524         },
9525
9526         /**
9527          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9528          * gradient background, rounded corners and a 4-way shadow.
9529          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9530          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9531          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9532          * @return {Roo.Element} this
9533          */
9534         boxWrap : function(cls){
9535             cls = cls || 'x-box';
9536             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9537             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9538             return el;
9539         },
9540
9541         /**
9542          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9543          * @param {String} namespace The namespace in which to look for the attribute
9544          * @param {String} name The attribute name
9545          * @return {String} The attribute value
9546          */
9547         getAttributeNS : Roo.isIE ? function(ns, name){
9548             var d = this.dom;
9549             var type = typeof d[ns+":"+name];
9550             if(type != 'undefined' && type != 'unknown'){
9551                 return d[ns+":"+name];
9552             }
9553             return d[name];
9554         } : function(ns, name){
9555             var d = this.dom;
9556             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9557         },
9558         
9559         
9560         /**
9561          * Sets or Returns the value the dom attribute value
9562          * @param {String} name The attribute name
9563          * @param {String} value (optional) The value to set the attribute to
9564          * @return {String} The attribute value
9565          */
9566         attr : function(name){
9567             if (arguments.length > 1) {
9568                 this.dom.setAttribute(name, arguments[1]);
9569                 return arguments[1];
9570             }
9571             if (!this.dom.hasAttribute(name)) {
9572                 return undefined;
9573             }
9574             return this.dom.getAttribute(name);
9575         }
9576         
9577         
9578         
9579     };
9580
9581     var ep = El.prototype;
9582
9583     /**
9584      * Appends an event handler (Shorthand for addListener)
9585      * @param {String}   eventName     The type of event to append
9586      * @param {Function} fn        The method the event invokes
9587      * @param {Object} scope       (optional) The scope (this object) of the fn
9588      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9589      * @method
9590      */
9591     ep.on = ep.addListener;
9592         // backwards compat
9593     ep.mon = ep.addListener;
9594
9595     /**
9596      * Removes an event handler from this element (shorthand for removeListener)
9597      * @param {String} eventName the type of event to remove
9598      * @param {Function} fn the method the event invokes
9599      * @return {Roo.Element} this
9600      * @method
9601      */
9602     ep.un = ep.removeListener;
9603
9604     /**
9605      * true to automatically adjust width and height settings for box-model issues (default to true)
9606      */
9607     ep.autoBoxAdjust = true;
9608
9609     // private
9610     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9611
9612     // private
9613     El.addUnits = function(v, defaultUnit){
9614         if(v === "" || v == "auto"){
9615             return v;
9616         }
9617         if(v === undefined){
9618             return '';
9619         }
9620         if(typeof v == "number" || !El.unitPattern.test(v)){
9621             return v + (defaultUnit || 'px');
9622         }
9623         return v;
9624     };
9625
9626     // special markup used throughout Roo when box wrapping elements
9627     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>';
9628     /**
9629      * Visibility mode constant - Use visibility to hide element
9630      * @static
9631      * @type Number
9632      */
9633     El.VISIBILITY = 1;
9634     /**
9635      * Visibility mode constant - Use display to hide element
9636      * @static
9637      * @type Number
9638      */
9639     El.DISPLAY = 2;
9640
9641     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9642     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9643     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9644
9645
9646
9647     /**
9648      * @private
9649      */
9650     El.cache = {};
9651
9652     var docEl;
9653
9654     /**
9655      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9656      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9657      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9658      * @return {Element} The Element object
9659      * @static
9660      */
9661     El.get = function(el){
9662         var ex, elm, id;
9663         if(!el){ return null; }
9664         if(typeof el == "string"){ // element id
9665             if(!(elm = document.getElementById(el))){
9666                 return null;
9667             }
9668             if(ex = El.cache[el]){
9669                 ex.dom = elm;
9670             }else{
9671                 ex = El.cache[el] = new El(elm);
9672             }
9673             return ex;
9674         }else if(el.tagName){ // dom element
9675             if(!(id = el.id)){
9676                 id = Roo.id(el);
9677             }
9678             if(ex = El.cache[id]){
9679                 ex.dom = el;
9680             }else{
9681                 ex = El.cache[id] = new El(el);
9682             }
9683             return ex;
9684         }else if(el instanceof El){
9685             if(el != docEl){
9686                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9687                                                               // catch case where it hasn't been appended
9688                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9689             }
9690             return el;
9691         }else if(el.isComposite){
9692             return el;
9693         }else if(el instanceof Array){
9694             return El.select(el);
9695         }else if(el == document){
9696             // create a bogus element object representing the document object
9697             if(!docEl){
9698                 var f = function(){};
9699                 f.prototype = El.prototype;
9700                 docEl = new f();
9701                 docEl.dom = document;
9702             }
9703             return docEl;
9704         }
9705         return null;
9706     };
9707
9708     // private
9709     El.uncache = function(el){
9710         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9711             if(a[i]){
9712                 delete El.cache[a[i].id || a[i]];
9713             }
9714         }
9715     };
9716
9717     // private
9718     // Garbage collection - uncache elements/purge listeners on orphaned elements
9719     // so we don't hold a reference and cause the browser to retain them
9720     El.garbageCollect = function(){
9721         if(!Roo.enableGarbageCollector){
9722             clearInterval(El.collectorThread);
9723             return;
9724         }
9725         for(var eid in El.cache){
9726             var el = El.cache[eid], d = el.dom;
9727             // -------------------------------------------------------
9728             // Determining what is garbage:
9729             // -------------------------------------------------------
9730             // !d
9731             // dom node is null, definitely garbage
9732             // -------------------------------------------------------
9733             // !d.parentNode
9734             // no parentNode == direct orphan, definitely garbage
9735             // -------------------------------------------------------
9736             // !d.offsetParent && !document.getElementById(eid)
9737             // display none elements have no offsetParent so we will
9738             // also try to look it up by it's id. However, check
9739             // offsetParent first so we don't do unneeded lookups.
9740             // This enables collection of elements that are not orphans
9741             // directly, but somewhere up the line they have an orphan
9742             // parent.
9743             // -------------------------------------------------------
9744             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9745                 delete El.cache[eid];
9746                 if(d && Roo.enableListenerCollection){
9747                     E.purgeElement(d);
9748                 }
9749             }
9750         }
9751     }
9752     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9753
9754
9755     // dom is optional
9756     El.Flyweight = function(dom){
9757         this.dom = dom;
9758     };
9759     El.Flyweight.prototype = El.prototype;
9760
9761     El._flyweights = {};
9762     /**
9763      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9764      * the dom node can be overwritten by other code.
9765      * @param {String/HTMLElement} el The dom node or id
9766      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9767      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9768      * @static
9769      * @return {Element} The shared Element object
9770      */
9771     El.fly = function(el, named){
9772         named = named || '_global';
9773         el = Roo.getDom(el);
9774         if(!el){
9775             return null;
9776         }
9777         if(!El._flyweights[named]){
9778             El._flyweights[named] = new El.Flyweight();
9779         }
9780         El._flyweights[named].dom = el;
9781         return El._flyweights[named];
9782     };
9783
9784     /**
9785      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9786      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9787      * Shorthand of {@link Roo.Element#get}
9788      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9789      * @return {Element} The Element object
9790      * @member Roo
9791      * @method get
9792      */
9793     Roo.get = El.get;
9794     /**
9795      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9796      * the dom node can be overwritten by other code.
9797      * Shorthand of {@link Roo.Element#fly}
9798      * @param {String/HTMLElement} el The dom node or id
9799      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9800      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9801      * @static
9802      * @return {Element} The shared Element object
9803      * @member Roo
9804      * @method fly
9805      */
9806     Roo.fly = El.fly;
9807
9808     // speedy lookup for elements never to box adjust
9809     var noBoxAdjust = Roo.isStrict ? {
9810         select:1
9811     } : {
9812         input:1, select:1, textarea:1
9813     };
9814     if(Roo.isIE || Roo.isGecko){
9815         noBoxAdjust['button'] = 1;
9816     }
9817
9818
9819     Roo.EventManager.on(window, 'unload', function(){
9820         delete El.cache;
9821         delete El._flyweights;
9822     });
9823 })();
9824
9825
9826
9827
9828 if(Roo.DomQuery){
9829     Roo.Element.selectorFunction = Roo.DomQuery.select;
9830 }
9831
9832 Roo.Element.select = function(selector, unique, root){
9833     var els;
9834     if(typeof selector == "string"){
9835         els = Roo.Element.selectorFunction(selector, root);
9836     }else if(selector.length !== undefined){
9837         els = selector;
9838     }else{
9839         throw "Invalid selector";
9840     }
9841     if(unique === true){
9842         return new Roo.CompositeElement(els);
9843     }else{
9844         return new Roo.CompositeElementLite(els);
9845     }
9846 };
9847 /**
9848  * Selects elements based on the passed CSS selector to enable working on them as 1.
9849  * @param {String/Array} selector The CSS selector or an array of elements
9850  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9851  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9852  * @return {CompositeElementLite/CompositeElement}
9853  * @member Roo
9854  * @method select
9855  */
9856 Roo.select = Roo.Element.select;
9857
9858
9859
9860
9861
9862
9863
9864
9865
9866
9867
9868
9869
9870
9871 /*
9872  * Based on:
9873  * Ext JS Library 1.1.1
9874  * Copyright(c) 2006-2007, Ext JS, LLC.
9875  *
9876  * Originally Released Under LGPL - original licence link has changed is not relivant.
9877  *
9878  * Fork - LGPL
9879  * <script type="text/javascript">
9880  */
9881
9882
9883
9884 //Notifies Element that fx methods are available
9885 Roo.enableFx = true;
9886
9887 /**
9888  * @class Roo.Fx
9889  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9890  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9891  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9892  * Element effects to work.</p><br/>
9893  *
9894  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9895  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9896  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9897  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9898  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9899  * expected results and should be done with care.</p><br/>
9900  *
9901  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9902  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9903 <pre>
9904 Value  Description
9905 -----  -----------------------------
9906 tl     The top left corner
9907 t      The center of the top edge
9908 tr     The top right corner
9909 l      The center of the left edge
9910 r      The center of the right edge
9911 bl     The bottom left corner
9912 b      The center of the bottom edge
9913 br     The bottom right corner
9914 </pre>
9915  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9916  * below are common options that can be passed to any Fx method.</b>
9917  * @cfg {Function} callback A function called when the effect is finished
9918  * @cfg {Object} scope The scope of the effect function
9919  * @cfg {String} easing A valid Easing value for the effect
9920  * @cfg {String} afterCls A css class to apply after the effect
9921  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9922  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9923  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9924  * effects that end with the element being visually hidden, ignored otherwise)
9925  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9926  * a function which returns such a specification that will be applied to the Element after the effect finishes
9927  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9928  * @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
9929  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9930  */
9931 Roo.Fx = {
9932         /**
9933          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9934          * origin for the slide effect.  This function automatically handles wrapping the element with
9935          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9936          * Usage:
9937          *<pre><code>
9938 // default: slide the element in from the top
9939 el.slideIn();
9940
9941 // custom: slide the element in from the right with a 2-second duration
9942 el.slideIn('r', { duration: 2 });
9943
9944 // common config options shown with default values
9945 el.slideIn('t', {
9946     easing: 'easeOut',
9947     duration: .5
9948 });
9949 </code></pre>
9950          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9951          * @param {Object} options (optional) Object literal with any of the Fx config options
9952          * @return {Roo.Element} The Element
9953          */
9954     slideIn : function(anchor, o){
9955         var el = this.getFxEl();
9956         o = o || {};
9957
9958         el.queueFx(o, function(){
9959
9960             anchor = anchor || "t";
9961
9962             // fix display to visibility
9963             this.fixDisplay();
9964
9965             // restore values after effect
9966             var r = this.getFxRestore();
9967             var b = this.getBox();
9968             // fixed size for slide
9969             this.setSize(b);
9970
9971             // wrap if needed
9972             var wrap = this.fxWrap(r.pos, o, "hidden");
9973
9974             var st = this.dom.style;
9975             st.visibility = "visible";
9976             st.position = "absolute";
9977
9978             // clear out temp styles after slide and unwrap
9979             var after = function(){
9980                 el.fxUnwrap(wrap, r.pos, o);
9981                 st.width = r.width;
9982                 st.height = r.height;
9983                 el.afterFx(o);
9984             };
9985             // time to calc the positions
9986             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9987
9988             switch(anchor.toLowerCase()){
9989                 case "t":
9990                     wrap.setSize(b.width, 0);
9991                     st.left = st.bottom = "0";
9992                     a = {height: bh};
9993                 break;
9994                 case "l":
9995                     wrap.setSize(0, b.height);
9996                     st.right = st.top = "0";
9997                     a = {width: bw};
9998                 break;
9999                 case "r":
10000                     wrap.setSize(0, b.height);
10001                     wrap.setX(b.right);
10002                     st.left = st.top = "0";
10003                     a = {width: bw, points: pt};
10004                 break;
10005                 case "b":
10006                     wrap.setSize(b.width, 0);
10007                     wrap.setY(b.bottom);
10008                     st.left = st.top = "0";
10009                     a = {height: bh, points: pt};
10010                 break;
10011                 case "tl":
10012                     wrap.setSize(0, 0);
10013                     st.right = st.bottom = "0";
10014                     a = {width: bw, height: bh};
10015                 break;
10016                 case "bl":
10017                     wrap.setSize(0, 0);
10018                     wrap.setY(b.y+b.height);
10019                     st.right = st.top = "0";
10020                     a = {width: bw, height: bh, points: pt};
10021                 break;
10022                 case "br":
10023                     wrap.setSize(0, 0);
10024                     wrap.setXY([b.right, b.bottom]);
10025                     st.left = st.top = "0";
10026                     a = {width: bw, height: bh, points: pt};
10027                 break;
10028                 case "tr":
10029                     wrap.setSize(0, 0);
10030                     wrap.setX(b.x+b.width);
10031                     st.left = st.bottom = "0";
10032                     a = {width: bw, height: bh, points: pt};
10033                 break;
10034             }
10035             this.dom.style.visibility = "visible";
10036             wrap.show();
10037
10038             arguments.callee.anim = wrap.fxanim(a,
10039                 o,
10040                 'motion',
10041                 .5,
10042                 'easeOut', after);
10043         });
10044         return this;
10045     },
10046     
10047         /**
10048          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10049          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10050          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10051          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10052          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10053          * Usage:
10054          *<pre><code>
10055 // default: slide the element out to the top
10056 el.slideOut();
10057
10058 // custom: slide the element out to the right with a 2-second duration
10059 el.slideOut('r', { duration: 2 });
10060
10061 // common config options shown with default values
10062 el.slideOut('t', {
10063     easing: 'easeOut',
10064     duration: .5,
10065     remove: false,
10066     useDisplay: false
10067 });
10068 </code></pre>
10069          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10070          * @param {Object} options (optional) Object literal with any of the Fx config options
10071          * @return {Roo.Element} The Element
10072          */
10073     slideOut : function(anchor, o){
10074         var el = this.getFxEl();
10075         o = o || {};
10076
10077         el.queueFx(o, function(){
10078
10079             anchor = anchor || "t";
10080
10081             // restore values after effect
10082             var r = this.getFxRestore();
10083             
10084             var b = this.getBox();
10085             // fixed size for slide
10086             this.setSize(b);
10087
10088             // wrap if needed
10089             var wrap = this.fxWrap(r.pos, o, "visible");
10090
10091             var st = this.dom.style;
10092             st.visibility = "visible";
10093             st.position = "absolute";
10094
10095             wrap.setSize(b);
10096
10097             var after = function(){
10098                 if(o.useDisplay){
10099                     el.setDisplayed(false);
10100                 }else{
10101                     el.hide();
10102                 }
10103
10104                 el.fxUnwrap(wrap, r.pos, o);
10105
10106                 st.width = r.width;
10107                 st.height = r.height;
10108
10109                 el.afterFx(o);
10110             };
10111
10112             var a, zero = {to: 0};
10113             switch(anchor.toLowerCase()){
10114                 case "t":
10115                     st.left = st.bottom = "0";
10116                     a = {height: zero};
10117                 break;
10118                 case "l":
10119                     st.right = st.top = "0";
10120                     a = {width: zero};
10121                 break;
10122                 case "r":
10123                     st.left = st.top = "0";
10124                     a = {width: zero, points: {to:[b.right, b.y]}};
10125                 break;
10126                 case "b":
10127                     st.left = st.top = "0";
10128                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10129                 break;
10130                 case "tl":
10131                     st.right = st.bottom = "0";
10132                     a = {width: zero, height: zero};
10133                 break;
10134                 case "bl":
10135                     st.right = st.top = "0";
10136                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10137                 break;
10138                 case "br":
10139                     st.left = st.top = "0";
10140                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10141                 break;
10142                 case "tr":
10143                     st.left = st.bottom = "0";
10144                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10145                 break;
10146             }
10147
10148             arguments.callee.anim = wrap.fxanim(a,
10149                 o,
10150                 'motion',
10151                 .5,
10152                 "easeOut", after);
10153         });
10154         return this;
10155     },
10156
10157         /**
10158          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10159          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10160          * The element must be removed from the DOM using the 'remove' config option if desired.
10161          * Usage:
10162          *<pre><code>
10163 // default
10164 el.puff();
10165
10166 // common config options shown with default values
10167 el.puff({
10168     easing: 'easeOut',
10169     duration: .5,
10170     remove: false,
10171     useDisplay: false
10172 });
10173 </code></pre>
10174          * @param {Object} options (optional) Object literal with any of the Fx config options
10175          * @return {Roo.Element} The Element
10176          */
10177     puff : function(o){
10178         var el = this.getFxEl();
10179         o = o || {};
10180
10181         el.queueFx(o, function(){
10182             this.clearOpacity();
10183             this.show();
10184
10185             // restore values after effect
10186             var r = this.getFxRestore();
10187             var st = this.dom.style;
10188
10189             var after = function(){
10190                 if(o.useDisplay){
10191                     el.setDisplayed(false);
10192                 }else{
10193                     el.hide();
10194                 }
10195
10196                 el.clearOpacity();
10197
10198                 el.setPositioning(r.pos);
10199                 st.width = r.width;
10200                 st.height = r.height;
10201                 st.fontSize = '';
10202                 el.afterFx(o);
10203             };
10204
10205             var width = this.getWidth();
10206             var height = this.getHeight();
10207
10208             arguments.callee.anim = this.fxanim({
10209                     width : {to: this.adjustWidth(width * 2)},
10210                     height : {to: this.adjustHeight(height * 2)},
10211                     points : {by: [-(width * .5), -(height * .5)]},
10212                     opacity : {to: 0},
10213                     fontSize: {to:200, unit: "%"}
10214                 },
10215                 o,
10216                 'motion',
10217                 .5,
10218                 "easeOut", after);
10219         });
10220         return this;
10221     },
10222
10223         /**
10224          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10225          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10226          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10227          * Usage:
10228          *<pre><code>
10229 // default
10230 el.switchOff();
10231
10232 // all config options shown with default values
10233 el.switchOff({
10234     easing: 'easeIn',
10235     duration: .3,
10236     remove: false,
10237     useDisplay: false
10238 });
10239 </code></pre>
10240          * @param {Object} options (optional) Object literal with any of the Fx config options
10241          * @return {Roo.Element} The Element
10242          */
10243     switchOff : function(o){
10244         var el = this.getFxEl();
10245         o = o || {};
10246
10247         el.queueFx(o, function(){
10248             this.clearOpacity();
10249             this.clip();
10250
10251             // restore values after effect
10252             var r = this.getFxRestore();
10253             var st = this.dom.style;
10254
10255             var after = function(){
10256                 if(o.useDisplay){
10257                     el.setDisplayed(false);
10258                 }else{
10259                     el.hide();
10260                 }
10261
10262                 el.clearOpacity();
10263                 el.setPositioning(r.pos);
10264                 st.width = r.width;
10265                 st.height = r.height;
10266
10267                 el.afterFx(o);
10268             };
10269
10270             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10271                 this.clearOpacity();
10272                 (function(){
10273                     this.fxanim({
10274                         height:{to:1},
10275                         points:{by:[0, this.getHeight() * .5]}
10276                     }, o, 'motion', 0.3, 'easeIn', after);
10277                 }).defer(100, this);
10278             });
10279         });
10280         return this;
10281     },
10282
10283     /**
10284      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10285      * changed using the "attr" config option) and then fading back to the original color. If no original
10286      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10287      * Usage:
10288 <pre><code>
10289 // default: highlight background to yellow
10290 el.highlight();
10291
10292 // custom: highlight foreground text to blue for 2 seconds
10293 el.highlight("0000ff", { attr: 'color', duration: 2 });
10294
10295 // common config options shown with default values
10296 el.highlight("ffff9c", {
10297     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10298     endColor: (current color) or "ffffff",
10299     easing: 'easeIn',
10300     duration: 1
10301 });
10302 </code></pre>
10303      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10304      * @param {Object} options (optional) Object literal with any of the Fx config options
10305      * @return {Roo.Element} The Element
10306      */ 
10307     highlight : function(color, o){
10308         var el = this.getFxEl();
10309         o = o || {};
10310
10311         el.queueFx(o, function(){
10312             color = color || "ffff9c";
10313             attr = o.attr || "backgroundColor";
10314
10315             this.clearOpacity();
10316             this.show();
10317
10318             var origColor = this.getColor(attr);
10319             var restoreColor = this.dom.style[attr];
10320             endColor = (o.endColor || origColor) || "ffffff";
10321
10322             var after = function(){
10323                 el.dom.style[attr] = restoreColor;
10324                 el.afterFx(o);
10325             };
10326
10327             var a = {};
10328             a[attr] = {from: color, to: endColor};
10329             arguments.callee.anim = this.fxanim(a,
10330                 o,
10331                 'color',
10332                 1,
10333                 'easeIn', after);
10334         });
10335         return this;
10336     },
10337
10338    /**
10339     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10340     * Usage:
10341 <pre><code>
10342 // default: a single light blue ripple
10343 el.frame();
10344
10345 // custom: 3 red ripples lasting 3 seconds total
10346 el.frame("ff0000", 3, { duration: 3 });
10347
10348 // common config options shown with default values
10349 el.frame("C3DAF9", 1, {
10350     duration: 1 //duration of entire animation (not each individual ripple)
10351     // Note: Easing is not configurable and will be ignored if included
10352 });
10353 </code></pre>
10354     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10355     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10356     * @param {Object} options (optional) Object literal with any of the Fx config options
10357     * @return {Roo.Element} The Element
10358     */
10359     frame : function(color, count, o){
10360         var el = this.getFxEl();
10361         o = o || {};
10362
10363         el.queueFx(o, function(){
10364             color = color || "#C3DAF9";
10365             if(color.length == 6){
10366                 color = "#" + color;
10367             }
10368             count = count || 1;
10369             duration = o.duration || 1;
10370             this.show();
10371
10372             var b = this.getBox();
10373             var animFn = function(){
10374                 var proxy = this.createProxy({
10375
10376                      style:{
10377                         visbility:"hidden",
10378                         position:"absolute",
10379                         "z-index":"35000", // yee haw
10380                         border:"0px solid " + color
10381                      }
10382                   });
10383                 var scale = Roo.isBorderBox ? 2 : 1;
10384                 proxy.animate({
10385                     top:{from:b.y, to:b.y - 20},
10386                     left:{from:b.x, to:b.x - 20},
10387                     borderWidth:{from:0, to:10},
10388                     opacity:{from:1, to:0},
10389                     height:{from:b.height, to:(b.height + (20*scale))},
10390                     width:{from:b.width, to:(b.width + (20*scale))}
10391                 }, duration, function(){
10392                     proxy.remove();
10393                 });
10394                 if(--count > 0){
10395                      animFn.defer((duration/2)*1000, this);
10396                 }else{
10397                     el.afterFx(o);
10398                 }
10399             };
10400             animFn.call(this);
10401         });
10402         return this;
10403     },
10404
10405    /**
10406     * Creates a pause before any subsequent queued effects begin.  If there are
10407     * no effects queued after the pause it will have no effect.
10408     * Usage:
10409 <pre><code>
10410 el.pause(1);
10411 </code></pre>
10412     * @param {Number} seconds The length of time to pause (in seconds)
10413     * @return {Roo.Element} The Element
10414     */
10415     pause : function(seconds){
10416         var el = this.getFxEl();
10417         var o = {};
10418
10419         el.queueFx(o, function(){
10420             setTimeout(function(){
10421                 el.afterFx(o);
10422             }, seconds * 1000);
10423         });
10424         return this;
10425     },
10426
10427    /**
10428     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10429     * using the "endOpacity" config option.
10430     * Usage:
10431 <pre><code>
10432 // default: fade in from opacity 0 to 100%
10433 el.fadeIn();
10434
10435 // custom: fade in from opacity 0 to 75% over 2 seconds
10436 el.fadeIn({ endOpacity: .75, duration: 2});
10437
10438 // common config options shown with default values
10439 el.fadeIn({
10440     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10441     easing: 'easeOut',
10442     duration: .5
10443 });
10444 </code></pre>
10445     * @param {Object} options (optional) Object literal with any of the Fx config options
10446     * @return {Roo.Element} The Element
10447     */
10448     fadeIn : function(o){
10449         var el = this.getFxEl();
10450         o = o || {};
10451         el.queueFx(o, function(){
10452             this.setOpacity(0);
10453             this.fixDisplay();
10454             this.dom.style.visibility = 'visible';
10455             var to = o.endOpacity || 1;
10456             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10457                 o, null, .5, "easeOut", function(){
10458                 if(to == 1){
10459                     this.clearOpacity();
10460                 }
10461                 el.afterFx(o);
10462             });
10463         });
10464         return this;
10465     },
10466
10467    /**
10468     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10469     * using the "endOpacity" config option.
10470     * Usage:
10471 <pre><code>
10472 // default: fade out from the element's current opacity to 0
10473 el.fadeOut();
10474
10475 // custom: fade out from the element's current opacity to 25% over 2 seconds
10476 el.fadeOut({ endOpacity: .25, duration: 2});
10477
10478 // common config options shown with default values
10479 el.fadeOut({
10480     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10481     easing: 'easeOut',
10482     duration: .5
10483     remove: false,
10484     useDisplay: false
10485 });
10486 </code></pre>
10487     * @param {Object} options (optional) Object literal with any of the Fx config options
10488     * @return {Roo.Element} The Element
10489     */
10490     fadeOut : function(o){
10491         var el = this.getFxEl();
10492         o = o || {};
10493         el.queueFx(o, function(){
10494             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10495                 o, null, .5, "easeOut", function(){
10496                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10497                      this.dom.style.display = "none";
10498                 }else{
10499                      this.dom.style.visibility = "hidden";
10500                 }
10501                 this.clearOpacity();
10502                 el.afterFx(o);
10503             });
10504         });
10505         return this;
10506     },
10507
10508    /**
10509     * Animates the transition of an element's dimensions from a starting height/width
10510     * to an ending height/width.
10511     * Usage:
10512 <pre><code>
10513 // change height and width to 100x100 pixels
10514 el.scale(100, 100);
10515
10516 // common config options shown with default values.  The height and width will default to
10517 // the element's existing values if passed as null.
10518 el.scale(
10519     [element's width],
10520     [element's height], {
10521     easing: 'easeOut',
10522     duration: .35
10523 });
10524 </code></pre>
10525     * @param {Number} width  The new width (pass undefined to keep the original width)
10526     * @param {Number} height  The new height (pass undefined to keep the original height)
10527     * @param {Object} options (optional) Object literal with any of the Fx config options
10528     * @return {Roo.Element} The Element
10529     */
10530     scale : function(w, h, o){
10531         this.shift(Roo.apply({}, o, {
10532             width: w,
10533             height: h
10534         }));
10535         return this;
10536     },
10537
10538    /**
10539     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10540     * Any of these properties not specified in the config object will not be changed.  This effect 
10541     * requires that at least one new dimension, position or opacity setting must be passed in on
10542     * the config object in order for the function to have any effect.
10543     * Usage:
10544 <pre><code>
10545 // slide the element horizontally to x position 200 while changing the height and opacity
10546 el.shift({ x: 200, height: 50, opacity: .8 });
10547
10548 // common config options shown with default values.
10549 el.shift({
10550     width: [element's width],
10551     height: [element's height],
10552     x: [element's x position],
10553     y: [element's y position],
10554     opacity: [element's opacity],
10555     easing: 'easeOut',
10556     duration: .35
10557 });
10558 </code></pre>
10559     * @param {Object} options  Object literal with any of the Fx config options
10560     * @return {Roo.Element} The Element
10561     */
10562     shift : function(o){
10563         var el = this.getFxEl();
10564         o = o || {};
10565         el.queueFx(o, function(){
10566             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10567             if(w !== undefined){
10568                 a.width = {to: this.adjustWidth(w)};
10569             }
10570             if(h !== undefined){
10571                 a.height = {to: this.adjustHeight(h)};
10572             }
10573             if(x !== undefined || y !== undefined){
10574                 a.points = {to: [
10575                     x !== undefined ? x : this.getX(),
10576                     y !== undefined ? y : this.getY()
10577                 ]};
10578             }
10579             if(op !== undefined){
10580                 a.opacity = {to: op};
10581             }
10582             if(o.xy !== undefined){
10583                 a.points = {to: o.xy};
10584             }
10585             arguments.callee.anim = this.fxanim(a,
10586                 o, 'motion', .35, "easeOut", function(){
10587                 el.afterFx(o);
10588             });
10589         });
10590         return this;
10591     },
10592
10593         /**
10594          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10595          * ending point of the effect.
10596          * Usage:
10597          *<pre><code>
10598 // default: slide the element downward while fading out
10599 el.ghost();
10600
10601 // custom: slide the element out to the right with a 2-second duration
10602 el.ghost('r', { duration: 2 });
10603
10604 // common config options shown with default values
10605 el.ghost('b', {
10606     easing: 'easeOut',
10607     duration: .5
10608     remove: false,
10609     useDisplay: false
10610 });
10611 </code></pre>
10612          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10613          * @param {Object} options (optional) Object literal with any of the Fx config options
10614          * @return {Roo.Element} The Element
10615          */
10616     ghost : function(anchor, o){
10617         var el = this.getFxEl();
10618         o = o || {};
10619
10620         el.queueFx(o, function(){
10621             anchor = anchor || "b";
10622
10623             // restore values after effect
10624             var r = this.getFxRestore();
10625             var w = this.getWidth(),
10626                 h = this.getHeight();
10627
10628             var st = this.dom.style;
10629
10630             var after = function(){
10631                 if(o.useDisplay){
10632                     el.setDisplayed(false);
10633                 }else{
10634                     el.hide();
10635                 }
10636
10637                 el.clearOpacity();
10638                 el.setPositioning(r.pos);
10639                 st.width = r.width;
10640                 st.height = r.height;
10641
10642                 el.afterFx(o);
10643             };
10644
10645             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10646             switch(anchor.toLowerCase()){
10647                 case "t":
10648                     pt.by = [0, -h];
10649                 break;
10650                 case "l":
10651                     pt.by = [-w, 0];
10652                 break;
10653                 case "r":
10654                     pt.by = [w, 0];
10655                 break;
10656                 case "b":
10657                     pt.by = [0, h];
10658                 break;
10659                 case "tl":
10660                     pt.by = [-w, -h];
10661                 break;
10662                 case "bl":
10663                     pt.by = [-w, h];
10664                 break;
10665                 case "br":
10666                     pt.by = [w, h];
10667                 break;
10668                 case "tr":
10669                     pt.by = [w, -h];
10670                 break;
10671             }
10672
10673             arguments.callee.anim = this.fxanim(a,
10674                 o,
10675                 'motion',
10676                 .5,
10677                 "easeOut", after);
10678         });
10679         return this;
10680     },
10681
10682         /**
10683          * Ensures that all effects queued after syncFx is called on the element are
10684          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10685          * @return {Roo.Element} The Element
10686          */
10687     syncFx : function(){
10688         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10689             block : false,
10690             concurrent : true,
10691             stopFx : false
10692         });
10693         return this;
10694     },
10695
10696         /**
10697          * Ensures that all effects queued after sequenceFx is called on the element are
10698          * run in sequence.  This is the opposite of {@link #syncFx}.
10699          * @return {Roo.Element} The Element
10700          */
10701     sequenceFx : function(){
10702         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10703             block : false,
10704             concurrent : false,
10705             stopFx : false
10706         });
10707         return this;
10708     },
10709
10710         /* @private */
10711     nextFx : function(){
10712         var ef = this.fxQueue[0];
10713         if(ef){
10714             ef.call(this);
10715         }
10716     },
10717
10718         /**
10719          * Returns true if the element has any effects actively running or queued, else returns false.
10720          * @return {Boolean} True if element has active effects, else false
10721          */
10722     hasActiveFx : function(){
10723         return this.fxQueue && this.fxQueue[0];
10724     },
10725
10726         /**
10727          * Stops any running effects and clears the element's internal effects queue if it contains
10728          * any additional effects that haven't started yet.
10729          * @return {Roo.Element} The Element
10730          */
10731     stopFx : function(){
10732         if(this.hasActiveFx()){
10733             var cur = this.fxQueue[0];
10734             if(cur && cur.anim && cur.anim.isAnimated()){
10735                 this.fxQueue = [cur]; // clear out others
10736                 cur.anim.stop(true);
10737             }
10738         }
10739         return this;
10740     },
10741
10742         /* @private */
10743     beforeFx : function(o){
10744         if(this.hasActiveFx() && !o.concurrent){
10745            if(o.stopFx){
10746                this.stopFx();
10747                return true;
10748            }
10749            return false;
10750         }
10751         return true;
10752     },
10753
10754         /**
10755          * Returns true if the element is currently blocking so that no other effect can be queued
10756          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10757          * used to ensure that an effect initiated by a user action runs to completion prior to the
10758          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10759          * @return {Boolean} True if blocking, else false
10760          */
10761     hasFxBlock : function(){
10762         var q = this.fxQueue;
10763         return q && q[0] && q[0].block;
10764     },
10765
10766         /* @private */
10767     queueFx : function(o, fn){
10768         if(!this.fxQueue){
10769             this.fxQueue = [];
10770         }
10771         if(!this.hasFxBlock()){
10772             Roo.applyIf(o, this.fxDefaults);
10773             if(!o.concurrent){
10774                 var run = this.beforeFx(o);
10775                 fn.block = o.block;
10776                 this.fxQueue.push(fn);
10777                 if(run){
10778                     this.nextFx();
10779                 }
10780             }else{
10781                 fn.call(this);
10782             }
10783         }
10784         return this;
10785     },
10786
10787         /* @private */
10788     fxWrap : function(pos, o, vis){
10789         var wrap;
10790         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10791             var wrapXY;
10792             if(o.fixPosition){
10793                 wrapXY = this.getXY();
10794             }
10795             var div = document.createElement("div");
10796             div.style.visibility = vis;
10797             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10798             wrap.setPositioning(pos);
10799             if(wrap.getStyle("position") == "static"){
10800                 wrap.position("relative");
10801             }
10802             this.clearPositioning('auto');
10803             wrap.clip();
10804             wrap.dom.appendChild(this.dom);
10805             if(wrapXY){
10806                 wrap.setXY(wrapXY);
10807             }
10808         }
10809         return wrap;
10810     },
10811
10812         /* @private */
10813     fxUnwrap : function(wrap, pos, o){
10814         this.clearPositioning();
10815         this.setPositioning(pos);
10816         if(!o.wrap){
10817             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10818             wrap.remove();
10819         }
10820     },
10821
10822         /* @private */
10823     getFxRestore : function(){
10824         var st = this.dom.style;
10825         return {pos: this.getPositioning(), width: st.width, height : st.height};
10826     },
10827
10828         /* @private */
10829     afterFx : function(o){
10830         if(o.afterStyle){
10831             this.applyStyles(o.afterStyle);
10832         }
10833         if(o.afterCls){
10834             this.addClass(o.afterCls);
10835         }
10836         if(o.remove === true){
10837             this.remove();
10838         }
10839         Roo.callback(o.callback, o.scope, [this]);
10840         if(!o.concurrent){
10841             this.fxQueue.shift();
10842             this.nextFx();
10843         }
10844     },
10845
10846         /* @private */
10847     getFxEl : function(){ // support for composite element fx
10848         return Roo.get(this.dom);
10849     },
10850
10851         /* @private */
10852     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10853         animType = animType || 'run';
10854         opt = opt || {};
10855         var anim = Roo.lib.Anim[animType](
10856             this.dom, args,
10857             (opt.duration || defaultDur) || .35,
10858             (opt.easing || defaultEase) || 'easeOut',
10859             function(){
10860                 Roo.callback(cb, this);
10861             },
10862             this
10863         );
10864         opt.anim = anim;
10865         return anim;
10866     }
10867 };
10868
10869 // backwords compat
10870 Roo.Fx.resize = Roo.Fx.scale;
10871
10872 //When included, Roo.Fx is automatically applied to Element so that all basic
10873 //effects are available directly via the Element API
10874 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10875  * Based on:
10876  * Ext JS Library 1.1.1
10877  * Copyright(c) 2006-2007, Ext JS, LLC.
10878  *
10879  * Originally Released Under LGPL - original licence link has changed is not relivant.
10880  *
10881  * Fork - LGPL
10882  * <script type="text/javascript">
10883  */
10884
10885
10886 /**
10887  * @class Roo.CompositeElement
10888  * Standard composite class. Creates a Roo.Element for every element in the collection.
10889  * <br><br>
10890  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10891  * actions will be performed on all the elements in this collection.</b>
10892  * <br><br>
10893  * All methods return <i>this</i> and can be chained.
10894  <pre><code>
10895  var els = Roo.select("#some-el div.some-class", true);
10896  // or select directly from an existing element
10897  var el = Roo.get('some-el');
10898  el.select('div.some-class', true);
10899
10900  els.setWidth(100); // all elements become 100 width
10901  els.hide(true); // all elements fade out and hide
10902  // or
10903  els.setWidth(100).hide(true);
10904  </code></pre>
10905  */
10906 Roo.CompositeElement = function(els){
10907     this.elements = [];
10908     this.addElements(els);
10909 };
10910 Roo.CompositeElement.prototype = {
10911     isComposite: true,
10912     addElements : function(els){
10913         if(!els) return this;
10914         if(typeof els == "string"){
10915             els = Roo.Element.selectorFunction(els);
10916         }
10917         var yels = this.elements;
10918         var index = yels.length-1;
10919         for(var i = 0, len = els.length; i < len; i++) {
10920                 yels[++index] = Roo.get(els[i]);
10921         }
10922         return this;
10923     },
10924
10925     /**
10926     * Clears this composite and adds the elements returned by the passed selector.
10927     * @param {String/Array} els A string CSS selector, an array of elements or an element
10928     * @return {CompositeElement} this
10929     */
10930     fill : function(els){
10931         this.elements = [];
10932         this.add(els);
10933         return this;
10934     },
10935
10936     /**
10937     * Filters this composite to only elements that match the passed selector.
10938     * @param {String} selector A string CSS selector
10939     * @return {CompositeElement} this
10940     */
10941     filter : function(selector){
10942         var els = [];
10943         this.each(function(el){
10944             if(el.is(selector)){
10945                 els[els.length] = el.dom;
10946             }
10947         });
10948         this.fill(els);
10949         return this;
10950     },
10951
10952     invoke : function(fn, args){
10953         var els = this.elements;
10954         for(var i = 0, len = els.length; i < len; i++) {
10955                 Roo.Element.prototype[fn].apply(els[i], args);
10956         }
10957         return this;
10958     },
10959     /**
10960     * Adds elements to this composite.
10961     * @param {String/Array} els A string CSS selector, an array of elements or an element
10962     * @return {CompositeElement} this
10963     */
10964     add : function(els){
10965         if(typeof els == "string"){
10966             this.addElements(Roo.Element.selectorFunction(els));
10967         }else if(els.length !== undefined){
10968             this.addElements(els);
10969         }else{
10970             this.addElements([els]);
10971         }
10972         return this;
10973     },
10974     /**
10975     * Calls the passed function passing (el, this, index) for each element in this composite.
10976     * @param {Function} fn The function to call
10977     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10978     * @return {CompositeElement} this
10979     */
10980     each : function(fn, scope){
10981         var els = this.elements;
10982         for(var i = 0, len = els.length; i < len; i++){
10983             if(fn.call(scope || els[i], els[i], this, i) === false) {
10984                 break;
10985             }
10986         }
10987         return this;
10988     },
10989
10990     /**
10991      * Returns the Element object at the specified index
10992      * @param {Number} index
10993      * @return {Roo.Element}
10994      */
10995     item : function(index){
10996         return this.elements[index] || null;
10997     },
10998
10999     /**
11000      * Returns the first Element
11001      * @return {Roo.Element}
11002      */
11003     first : function(){
11004         return this.item(0);
11005     },
11006
11007     /**
11008      * Returns the last Element
11009      * @return {Roo.Element}
11010      */
11011     last : function(){
11012         return this.item(this.elements.length-1);
11013     },
11014
11015     /**
11016      * Returns the number of elements in this composite
11017      * @return Number
11018      */
11019     getCount : function(){
11020         return this.elements.length;
11021     },
11022
11023     /**
11024      * Returns true if this composite contains the passed element
11025      * @return Boolean
11026      */
11027     contains : function(el){
11028         return this.indexOf(el) !== -1;
11029     },
11030
11031     /**
11032      * Returns true if this composite contains the passed element
11033      * @return Boolean
11034      */
11035     indexOf : function(el){
11036         return this.elements.indexOf(Roo.get(el));
11037     },
11038
11039
11040     /**
11041     * Removes the specified element(s).
11042     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11043     * or an array of any of those.
11044     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11045     * @return {CompositeElement} this
11046     */
11047     removeElement : function(el, removeDom){
11048         if(el instanceof Array){
11049             for(var i = 0, len = el.length; i < len; i++){
11050                 this.removeElement(el[i]);
11051             }
11052             return this;
11053         }
11054         var index = typeof el == 'number' ? el : this.indexOf(el);
11055         if(index !== -1){
11056             if(removeDom){
11057                 var d = this.elements[index];
11058                 if(d.dom){
11059                     d.remove();
11060                 }else{
11061                     d.parentNode.removeChild(d);
11062                 }
11063             }
11064             this.elements.splice(index, 1);
11065         }
11066         return this;
11067     },
11068
11069     /**
11070     * Replaces the specified element with the passed element.
11071     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11072     * to replace.
11073     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11074     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11075     * @return {CompositeElement} this
11076     */
11077     replaceElement : function(el, replacement, domReplace){
11078         var index = typeof el == 'number' ? el : this.indexOf(el);
11079         if(index !== -1){
11080             if(domReplace){
11081                 this.elements[index].replaceWith(replacement);
11082             }else{
11083                 this.elements.splice(index, 1, Roo.get(replacement))
11084             }
11085         }
11086         return this;
11087     },
11088
11089     /**
11090      * Removes all elements.
11091      */
11092     clear : function(){
11093         this.elements = [];
11094     }
11095 };
11096 (function(){
11097     Roo.CompositeElement.createCall = function(proto, fnName){
11098         if(!proto[fnName]){
11099             proto[fnName] = function(){
11100                 return this.invoke(fnName, arguments);
11101             };
11102         }
11103     };
11104     for(var fnName in Roo.Element.prototype){
11105         if(typeof Roo.Element.prototype[fnName] == "function"){
11106             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11107         }
11108     };
11109 })();
11110 /*
11111  * Based on:
11112  * Ext JS Library 1.1.1
11113  * Copyright(c) 2006-2007, Ext JS, LLC.
11114  *
11115  * Originally Released Under LGPL - original licence link has changed is not relivant.
11116  *
11117  * Fork - LGPL
11118  * <script type="text/javascript">
11119  */
11120
11121 /**
11122  * @class Roo.CompositeElementLite
11123  * @extends Roo.CompositeElement
11124  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11125  <pre><code>
11126  var els = Roo.select("#some-el div.some-class");
11127  // or select directly from an existing element
11128  var el = Roo.get('some-el');
11129  el.select('div.some-class');
11130
11131  els.setWidth(100); // all elements become 100 width
11132  els.hide(true); // all elements fade out and hide
11133  // or
11134  els.setWidth(100).hide(true);
11135  </code></pre><br><br>
11136  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11137  * actions will be performed on all the elements in this collection.</b>
11138  */
11139 Roo.CompositeElementLite = function(els){
11140     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11141     this.el = new Roo.Element.Flyweight();
11142 };
11143 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11144     addElements : function(els){
11145         if(els){
11146             if(els instanceof Array){
11147                 this.elements = this.elements.concat(els);
11148             }else{
11149                 var yels = this.elements;
11150                 var index = yels.length-1;
11151                 for(var i = 0, len = els.length; i < len; i++) {
11152                     yels[++index] = els[i];
11153                 }
11154             }
11155         }
11156         return this;
11157     },
11158     invoke : function(fn, args){
11159         var els = this.elements;
11160         var el = this.el;
11161         for(var i = 0, len = els.length; i < len; i++) {
11162             el.dom = els[i];
11163                 Roo.Element.prototype[fn].apply(el, args);
11164         }
11165         return this;
11166     },
11167     /**
11168      * Returns a flyweight Element of the dom element object at the specified index
11169      * @param {Number} index
11170      * @return {Roo.Element}
11171      */
11172     item : function(index){
11173         if(!this.elements[index]){
11174             return null;
11175         }
11176         this.el.dom = this.elements[index];
11177         return this.el;
11178     },
11179
11180     // fixes scope with flyweight
11181     addListener : function(eventName, handler, scope, opt){
11182         var els = this.elements;
11183         for(var i = 0, len = els.length; i < len; i++) {
11184             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11185         }
11186         return this;
11187     },
11188
11189     /**
11190     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11191     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11192     * a reference to the dom node, use el.dom.</b>
11193     * @param {Function} fn The function to call
11194     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11195     * @return {CompositeElement} this
11196     */
11197     each : function(fn, scope){
11198         var els = this.elements;
11199         var el = this.el;
11200         for(var i = 0, len = els.length; i < len; i++){
11201             el.dom = els[i];
11202                 if(fn.call(scope || el, el, this, i) === false){
11203                 break;
11204             }
11205         }
11206         return this;
11207     },
11208
11209     indexOf : function(el){
11210         return this.elements.indexOf(Roo.getDom(el));
11211     },
11212
11213     replaceElement : function(el, replacement, domReplace){
11214         var index = typeof el == 'number' ? el : this.indexOf(el);
11215         if(index !== -1){
11216             replacement = Roo.getDom(replacement);
11217             if(domReplace){
11218                 var d = this.elements[index];
11219                 d.parentNode.insertBefore(replacement, d);
11220                 d.parentNode.removeChild(d);
11221             }
11222             this.elements.splice(index, 1, replacement);
11223         }
11224         return this;
11225     }
11226 });
11227 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11228
11229 /*
11230  * Based on:
11231  * Ext JS Library 1.1.1
11232  * Copyright(c) 2006-2007, Ext JS, LLC.
11233  *
11234  * Originally Released Under LGPL - original licence link has changed is not relivant.
11235  *
11236  * Fork - LGPL
11237  * <script type="text/javascript">
11238  */
11239
11240  
11241
11242 /**
11243  * @class Roo.data.Connection
11244  * @extends Roo.util.Observable
11245  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11246  * either to a configured URL, or to a URL specified at request time.<br><br>
11247  * <p>
11248  * Requests made by this class are asynchronous, and will return immediately. No data from
11249  * the server will be available to the statement immediately following the {@link #request} call.
11250  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11251  * <p>
11252  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11253  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11254  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11255  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11256  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11257  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11258  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11259  * standard DOM methods.
11260  * @constructor
11261  * @param {Object} config a configuration object.
11262  */
11263 Roo.data.Connection = function(config){
11264     Roo.apply(this, config);
11265     this.addEvents({
11266         /**
11267          * @event beforerequest
11268          * Fires before a network request is made to retrieve a data object.
11269          * @param {Connection} conn This Connection object.
11270          * @param {Object} options The options config object passed to the {@link #request} method.
11271          */
11272         "beforerequest" : true,
11273         /**
11274          * @event requestcomplete
11275          * Fires if the request was successfully completed.
11276          * @param {Connection} conn This Connection object.
11277          * @param {Object} response The XHR object containing the response data.
11278          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11279          * @param {Object} options The options config object passed to the {@link #request} method.
11280          */
11281         "requestcomplete" : true,
11282         /**
11283          * @event requestexception
11284          * Fires if an error HTTP status was returned from the server.
11285          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11286          * @param {Connection} conn This Connection object.
11287          * @param {Object} response The XHR object containing the response data.
11288          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11289          * @param {Object} options The options config object passed to the {@link #request} method.
11290          */
11291         "requestexception" : true
11292     });
11293     Roo.data.Connection.superclass.constructor.call(this);
11294 };
11295
11296 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11297     /**
11298      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11299      */
11300     /**
11301      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11302      * extra parameters to each request made by this object. (defaults to undefined)
11303      */
11304     /**
11305      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11306      *  to each request made by this object. (defaults to undefined)
11307      */
11308     /**
11309      * @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)
11310      */
11311     /**
11312      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11313      */
11314     timeout : 30000,
11315     /**
11316      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11317      * @type Boolean
11318      */
11319     autoAbort:false,
11320
11321     /**
11322      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11323      * @type Boolean
11324      */
11325     disableCaching: true,
11326
11327     /**
11328      * Sends an HTTP request to a remote server.
11329      * @param {Object} options An object which may contain the following properties:<ul>
11330      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11331      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11332      * request, a url encoded string or a function to call to get either.</li>
11333      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11334      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11335      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11336      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11337      * <li>options {Object} The parameter to the request call.</li>
11338      * <li>success {Boolean} True if the request succeeded.</li>
11339      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11340      * </ul></li>
11341      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11342      * The callback is passed the following parameters:<ul>
11343      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11344      * <li>options {Object} The parameter to the request call.</li>
11345      * </ul></li>
11346      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11347      * The callback is passed the following parameters:<ul>
11348      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11349      * <li>options {Object} The parameter to the request call.</li>
11350      * </ul></li>
11351      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11352      * for the callback function. Defaults to the browser window.</li>
11353      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11354      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11355      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11356      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11357      * params for the post data. Any params will be appended to the URL.</li>
11358      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11359      * </ul>
11360      * @return {Number} transactionId
11361      */
11362     request : function(o){
11363         if(this.fireEvent("beforerequest", this, o) !== false){
11364             var p = o.params;
11365
11366             if(typeof p == "function"){
11367                 p = p.call(o.scope||window, o);
11368             }
11369             if(typeof p == "object"){
11370                 p = Roo.urlEncode(o.params);
11371             }
11372             if(this.extraParams){
11373                 var extras = Roo.urlEncode(this.extraParams);
11374                 p = p ? (p + '&' + extras) : extras;
11375             }
11376
11377             var url = o.url || this.url;
11378             if(typeof url == 'function'){
11379                 url = url.call(o.scope||window, o);
11380             }
11381
11382             if(o.form){
11383                 var form = Roo.getDom(o.form);
11384                 url = url || form.action;
11385
11386                 var enctype = form.getAttribute("enctype");
11387                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11388                     return this.doFormUpload(o, p, url);
11389                 }
11390                 var f = Roo.lib.Ajax.serializeForm(form);
11391                 p = p ? (p + '&' + f) : f;
11392             }
11393
11394             var hs = o.headers;
11395             if(this.defaultHeaders){
11396                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11397                 if(!o.headers){
11398                     o.headers = hs;
11399                 }
11400             }
11401
11402             var cb = {
11403                 success: this.handleResponse,
11404                 failure: this.handleFailure,
11405                 scope: this,
11406                 argument: {options: o},
11407                 timeout : o.timeout || this.timeout
11408             };
11409
11410             var method = o.method||this.method||(p ? "POST" : "GET");
11411
11412             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11413                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11414             }
11415
11416             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11417                 if(o.autoAbort){
11418                     this.abort();
11419                 }
11420             }else if(this.autoAbort !== false){
11421                 this.abort();
11422             }
11423
11424             if((method == 'GET' && p) || o.xmlData){
11425                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11426                 p = '';
11427             }
11428             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11429             return this.transId;
11430         }else{
11431             Roo.callback(o.callback, o.scope, [o, null, null]);
11432             return null;
11433         }
11434     },
11435
11436     /**
11437      * Determine whether this object has a request outstanding.
11438      * @param {Number} transactionId (Optional) defaults to the last transaction
11439      * @return {Boolean} True if there is an outstanding request.
11440      */
11441     isLoading : function(transId){
11442         if(transId){
11443             return Roo.lib.Ajax.isCallInProgress(transId);
11444         }else{
11445             return this.transId ? true : false;
11446         }
11447     },
11448
11449     /**
11450      * Aborts any outstanding request.
11451      * @param {Number} transactionId (Optional) defaults to the last transaction
11452      */
11453     abort : function(transId){
11454         if(transId || this.isLoading()){
11455             Roo.lib.Ajax.abort(transId || this.transId);
11456         }
11457     },
11458
11459     // private
11460     handleResponse : function(response){
11461         this.transId = false;
11462         var options = response.argument.options;
11463         response.argument = options ? options.argument : null;
11464         this.fireEvent("requestcomplete", this, response, options);
11465         Roo.callback(options.success, options.scope, [response, options]);
11466         Roo.callback(options.callback, options.scope, [options, true, response]);
11467     },
11468
11469     // private
11470     handleFailure : function(response, e){
11471         this.transId = false;
11472         var options = response.argument.options;
11473         response.argument = options ? options.argument : null;
11474         this.fireEvent("requestexception", this, response, options, e);
11475         Roo.callback(options.failure, options.scope, [response, options]);
11476         Roo.callback(options.callback, options.scope, [options, false, response]);
11477     },
11478
11479     // private
11480     doFormUpload : function(o, ps, url){
11481         var id = Roo.id();
11482         var frame = document.createElement('iframe');
11483         frame.id = id;
11484         frame.name = id;
11485         frame.className = 'x-hidden';
11486         if(Roo.isIE){
11487             frame.src = Roo.SSL_SECURE_URL;
11488         }
11489         document.body.appendChild(frame);
11490
11491         if(Roo.isIE){
11492            document.frames[id].name = id;
11493         }
11494
11495         var form = Roo.getDom(o.form);
11496         form.target = id;
11497         form.method = 'POST';
11498         form.enctype = form.encoding = 'multipart/form-data';
11499         if(url){
11500             form.action = url;
11501         }
11502
11503         var hiddens, hd;
11504         if(ps){ // add dynamic params
11505             hiddens = [];
11506             ps = Roo.urlDecode(ps, false);
11507             for(var k in ps){
11508                 if(ps.hasOwnProperty(k)){
11509                     hd = document.createElement('input');
11510                     hd.type = 'hidden';
11511                     hd.name = k;
11512                     hd.value = ps[k];
11513                     form.appendChild(hd);
11514                     hiddens.push(hd);
11515                 }
11516             }
11517         }
11518
11519         function cb(){
11520             var r = {  // bogus response object
11521                 responseText : '',
11522                 responseXML : null
11523             };
11524
11525             r.argument = o ? o.argument : null;
11526
11527             try { //
11528                 var doc;
11529                 if(Roo.isIE){
11530                     doc = frame.contentWindow.document;
11531                 }else {
11532                     doc = (frame.contentDocument || window.frames[id].document);
11533                 }
11534                 if(doc && doc.body){
11535                     r.responseText = doc.body.innerHTML;
11536                 }
11537                 if(doc && doc.XMLDocument){
11538                     r.responseXML = doc.XMLDocument;
11539                 }else {
11540                     r.responseXML = doc;
11541                 }
11542             }
11543             catch(e) {
11544                 // ignore
11545             }
11546
11547             Roo.EventManager.removeListener(frame, 'load', cb, this);
11548
11549             this.fireEvent("requestcomplete", this, r, o);
11550             Roo.callback(o.success, o.scope, [r, o]);
11551             Roo.callback(o.callback, o.scope, [o, true, r]);
11552
11553             setTimeout(function(){document.body.removeChild(frame);}, 100);
11554         }
11555
11556         Roo.EventManager.on(frame, 'load', cb, this);
11557         form.submit();
11558
11559         if(hiddens){ // remove dynamic params
11560             for(var i = 0, len = hiddens.length; i < len; i++){
11561                 form.removeChild(hiddens[i]);
11562             }
11563         }
11564     }
11565 });
11566 /*
11567  * Based on:
11568  * Ext JS Library 1.1.1
11569  * Copyright(c) 2006-2007, Ext JS, LLC.
11570  *
11571  * Originally Released Under LGPL - original licence link has changed is not relivant.
11572  *
11573  * Fork - LGPL
11574  * <script type="text/javascript">
11575  */
11576  
11577 /**
11578  * Global Ajax request class.
11579  * 
11580  * @class Roo.Ajax
11581  * @extends Roo.data.Connection
11582  * @static
11583  * 
11584  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11585  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11586  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11587  * @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)
11588  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11589  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11590  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11591  */
11592 Roo.Ajax = new Roo.data.Connection({
11593     // fix up the docs
11594     /**
11595      * @scope Roo.Ajax
11596      * @type {Boolear} 
11597      */
11598     autoAbort : false,
11599
11600     /**
11601      * Serialize the passed form into a url encoded string
11602      * @scope Roo.Ajax
11603      * @param {String/HTMLElement} form
11604      * @return {String}
11605      */
11606     serializeForm : function(form){
11607         return Roo.lib.Ajax.serializeForm(form);
11608     }
11609 });/*
11610  * Based on:
11611  * Ext JS Library 1.1.1
11612  * Copyright(c) 2006-2007, Ext JS, LLC.
11613  *
11614  * Originally Released Under LGPL - original licence link has changed is not relivant.
11615  *
11616  * Fork - LGPL
11617  * <script type="text/javascript">
11618  */
11619
11620  
11621 /**
11622  * @class Roo.UpdateManager
11623  * @extends Roo.util.Observable
11624  * Provides AJAX-style update for Element object.<br><br>
11625  * Usage:<br>
11626  * <pre><code>
11627  * // Get it from a Roo.Element object
11628  * var el = Roo.get("foo");
11629  * var mgr = el.getUpdateManager();
11630  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11631  * ...
11632  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11633  * <br>
11634  * // or directly (returns the same UpdateManager instance)
11635  * var mgr = new Roo.UpdateManager("myElementId");
11636  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11637  * mgr.on("update", myFcnNeedsToKnow);
11638  * <br>
11639    // short handed call directly from the element object
11640    Roo.get("foo").load({
11641         url: "bar.php",
11642         scripts:true,
11643         params: "for=bar",
11644         text: "Loading Foo..."
11645    });
11646  * </code></pre>
11647  * @constructor
11648  * Create new UpdateManager directly.
11649  * @param {String/HTMLElement/Roo.Element} el The element to update
11650  * @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).
11651  */
11652 Roo.UpdateManager = function(el, forceNew){
11653     el = Roo.get(el);
11654     if(!forceNew && el.updateManager){
11655         return el.updateManager;
11656     }
11657     /**
11658      * The Element object
11659      * @type Roo.Element
11660      */
11661     this.el = el;
11662     /**
11663      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11664      * @type String
11665      */
11666     this.defaultUrl = null;
11667
11668     this.addEvents({
11669         /**
11670          * @event beforeupdate
11671          * Fired before an update is made, return false from your handler and the update is cancelled.
11672          * @param {Roo.Element} el
11673          * @param {String/Object/Function} url
11674          * @param {String/Object} params
11675          */
11676         "beforeupdate": true,
11677         /**
11678          * @event update
11679          * Fired after successful update is made.
11680          * @param {Roo.Element} el
11681          * @param {Object} oResponseObject The response Object
11682          */
11683         "update": true,
11684         /**
11685          * @event failure
11686          * Fired on update failure.
11687          * @param {Roo.Element} el
11688          * @param {Object} oResponseObject The response Object
11689          */
11690         "failure": true
11691     });
11692     var d = Roo.UpdateManager.defaults;
11693     /**
11694      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11695      * @type String
11696      */
11697     this.sslBlankUrl = d.sslBlankUrl;
11698     /**
11699      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11700      * @type Boolean
11701      */
11702     this.disableCaching = d.disableCaching;
11703     /**
11704      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11705      * @type String
11706      */
11707     this.indicatorText = d.indicatorText;
11708     /**
11709      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11710      * @type String
11711      */
11712     this.showLoadIndicator = d.showLoadIndicator;
11713     /**
11714      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11715      * @type Number
11716      */
11717     this.timeout = d.timeout;
11718
11719     /**
11720      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11721      * @type Boolean
11722      */
11723     this.loadScripts = d.loadScripts;
11724
11725     /**
11726      * Transaction object of current executing transaction
11727      */
11728     this.transaction = null;
11729
11730     /**
11731      * @private
11732      */
11733     this.autoRefreshProcId = null;
11734     /**
11735      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11736      * @type Function
11737      */
11738     this.refreshDelegate = this.refresh.createDelegate(this);
11739     /**
11740      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11741      * @type Function
11742      */
11743     this.updateDelegate = this.update.createDelegate(this);
11744     /**
11745      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11746      * @type Function
11747      */
11748     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11749     /**
11750      * @private
11751      */
11752     this.successDelegate = this.processSuccess.createDelegate(this);
11753     /**
11754      * @private
11755      */
11756     this.failureDelegate = this.processFailure.createDelegate(this);
11757
11758     if(!this.renderer){
11759      /**
11760       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11761       */
11762     this.renderer = new Roo.UpdateManager.BasicRenderer();
11763     }
11764     
11765     Roo.UpdateManager.superclass.constructor.call(this);
11766 };
11767
11768 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11769     /**
11770      * Get the Element this UpdateManager is bound to
11771      * @return {Roo.Element} The element
11772      */
11773     getEl : function(){
11774         return this.el;
11775     },
11776     /**
11777      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11778      * @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:
11779 <pre><code>
11780 um.update({<br/>
11781     url: "your-url.php",<br/>
11782     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11783     callback: yourFunction,<br/>
11784     scope: yourObject, //(optional scope)  <br/>
11785     discardUrl: false, <br/>
11786     nocache: false,<br/>
11787     text: "Loading...",<br/>
11788     timeout: 30,<br/>
11789     scripts: false<br/>
11790 });
11791 </code></pre>
11792      * The only required property is url. The optional properties nocache, text and scripts
11793      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11794      * @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}
11795      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11796      * @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.
11797      */
11798     update : function(url, params, callback, discardUrl){
11799         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11800             var method = this.method,
11801                 cfg;
11802             if(typeof url == "object"){ // must be config object
11803                 cfg = url;
11804                 url = cfg.url;
11805                 params = params || cfg.params;
11806                 callback = callback || cfg.callback;
11807                 discardUrl = discardUrl || cfg.discardUrl;
11808                 if(callback && cfg.scope){
11809                     callback = callback.createDelegate(cfg.scope);
11810                 }
11811                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11812                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11813                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11814                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11815                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11816             }
11817             this.showLoading();
11818             if(!discardUrl){
11819                 this.defaultUrl = url;
11820             }
11821             if(typeof url == "function"){
11822                 url = url.call(this);
11823             }
11824
11825             method = method || (params ? "POST" : "GET");
11826             if(method == "GET"){
11827                 url = this.prepareUrl(url);
11828             }
11829
11830             var o = Roo.apply(cfg ||{}, {
11831                 url : url,
11832                 params: params,
11833                 success: this.successDelegate,
11834                 failure: this.failureDelegate,
11835                 callback: undefined,
11836                 timeout: (this.timeout*1000),
11837                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11838             });
11839             Roo.log("updated manager called with timeout of " + o.timeout);
11840             this.transaction = Roo.Ajax.request(o);
11841         }
11842     },
11843
11844     /**
11845      * 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.
11846      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11847      * @param {String/HTMLElement} form The form Id or form element
11848      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11849      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11850      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11851      */
11852     formUpdate : function(form, url, reset, callback){
11853         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11854             if(typeof url == "function"){
11855                 url = url.call(this);
11856             }
11857             form = Roo.getDom(form);
11858             this.transaction = Roo.Ajax.request({
11859                 form: form,
11860                 url:url,
11861                 success: this.successDelegate,
11862                 failure: this.failureDelegate,
11863                 timeout: (this.timeout*1000),
11864                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11865             });
11866             this.showLoading.defer(1, this);
11867         }
11868     },
11869
11870     /**
11871      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11872      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11873      */
11874     refresh : function(callback){
11875         if(this.defaultUrl == null){
11876             return;
11877         }
11878         this.update(this.defaultUrl, null, callback, true);
11879     },
11880
11881     /**
11882      * Set this element to auto refresh.
11883      * @param {Number} interval How often to update (in seconds).
11884      * @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)
11885      * @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}
11886      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11887      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11888      */
11889     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11890         if(refreshNow){
11891             this.update(url || this.defaultUrl, params, callback, true);
11892         }
11893         if(this.autoRefreshProcId){
11894             clearInterval(this.autoRefreshProcId);
11895         }
11896         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11897     },
11898
11899     /**
11900      * Stop auto refresh on this element.
11901      */
11902      stopAutoRefresh : function(){
11903         if(this.autoRefreshProcId){
11904             clearInterval(this.autoRefreshProcId);
11905             delete this.autoRefreshProcId;
11906         }
11907     },
11908
11909     isAutoRefreshing : function(){
11910        return this.autoRefreshProcId ? true : false;
11911     },
11912     /**
11913      * Called to update the element to "Loading" state. Override to perform custom action.
11914      */
11915     showLoading : function(){
11916         if(this.showLoadIndicator){
11917             this.el.update(this.indicatorText);
11918         }
11919     },
11920
11921     /**
11922      * Adds unique parameter to query string if disableCaching = true
11923      * @private
11924      */
11925     prepareUrl : function(url){
11926         if(this.disableCaching){
11927             var append = "_dc=" + (new Date().getTime());
11928             if(url.indexOf("?") !== -1){
11929                 url += "&" + append;
11930             }else{
11931                 url += "?" + append;
11932             }
11933         }
11934         return url;
11935     },
11936
11937     /**
11938      * @private
11939      */
11940     processSuccess : function(response){
11941         this.transaction = null;
11942         if(response.argument.form && response.argument.reset){
11943             try{ // put in try/catch since some older FF releases had problems with this
11944                 response.argument.form.reset();
11945             }catch(e){}
11946         }
11947         if(this.loadScripts){
11948             this.renderer.render(this.el, response, this,
11949                 this.updateComplete.createDelegate(this, [response]));
11950         }else{
11951             this.renderer.render(this.el, response, this);
11952             this.updateComplete(response);
11953         }
11954     },
11955
11956     updateComplete : function(response){
11957         this.fireEvent("update", this.el, response);
11958         if(typeof response.argument.callback == "function"){
11959             response.argument.callback(this.el, true, response);
11960         }
11961     },
11962
11963     /**
11964      * @private
11965      */
11966     processFailure : function(response){
11967         this.transaction = null;
11968         this.fireEvent("failure", this.el, response);
11969         if(typeof response.argument.callback == "function"){
11970             response.argument.callback(this.el, false, response);
11971         }
11972     },
11973
11974     /**
11975      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11976      * @param {Object} renderer The object implementing the render() method
11977      */
11978     setRenderer : function(renderer){
11979         this.renderer = renderer;
11980     },
11981
11982     getRenderer : function(){
11983        return this.renderer;
11984     },
11985
11986     /**
11987      * Set the defaultUrl used for updates
11988      * @param {String/Function} defaultUrl The url or a function to call to get the url
11989      */
11990     setDefaultUrl : function(defaultUrl){
11991         this.defaultUrl = defaultUrl;
11992     },
11993
11994     /**
11995      * Aborts the executing transaction
11996      */
11997     abort : function(){
11998         if(this.transaction){
11999             Roo.Ajax.abort(this.transaction);
12000         }
12001     },
12002
12003     /**
12004      * Returns true if an update is in progress
12005      * @return {Boolean}
12006      */
12007     isUpdating : function(){
12008         if(this.transaction){
12009             return Roo.Ajax.isLoading(this.transaction);
12010         }
12011         return false;
12012     }
12013 });
12014
12015 /**
12016  * @class Roo.UpdateManager.defaults
12017  * @static (not really - but it helps the doc tool)
12018  * The defaults collection enables customizing the default properties of UpdateManager
12019  */
12020    Roo.UpdateManager.defaults = {
12021        /**
12022          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12023          * @type Number
12024          */
12025          timeout : 30,
12026
12027          /**
12028          * True to process scripts by default (Defaults to false).
12029          * @type Boolean
12030          */
12031         loadScripts : false,
12032
12033         /**
12034         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12035         * @type String
12036         */
12037         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12038         /**
12039          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12040          * @type Boolean
12041          */
12042         disableCaching : false,
12043         /**
12044          * Whether to show indicatorText when loading (Defaults to true).
12045          * @type Boolean
12046          */
12047         showLoadIndicator : true,
12048         /**
12049          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12050          * @type String
12051          */
12052         indicatorText : '<div class="loading-indicator">Loading...</div>'
12053    };
12054
12055 /**
12056  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12057  *Usage:
12058  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12059  * @param {String/HTMLElement/Roo.Element} el The element to update
12060  * @param {String} url The url
12061  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12062  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12063  * @static
12064  * @deprecated
12065  * @member Roo.UpdateManager
12066  */
12067 Roo.UpdateManager.updateElement = function(el, url, params, options){
12068     var um = Roo.get(el, true).getUpdateManager();
12069     Roo.apply(um, options);
12070     um.update(url, params, options ? options.callback : null);
12071 };
12072 // alias for backwards compat
12073 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12074 /**
12075  * @class Roo.UpdateManager.BasicRenderer
12076  * Default Content renderer. Updates the elements innerHTML with the responseText.
12077  */
12078 Roo.UpdateManager.BasicRenderer = function(){};
12079
12080 Roo.UpdateManager.BasicRenderer.prototype = {
12081     /**
12082      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12083      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12084      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12085      * @param {Roo.Element} el The element being rendered
12086      * @param {Object} response The YUI Connect response object
12087      * @param {UpdateManager} updateManager The calling update manager
12088      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12089      */
12090      render : function(el, response, updateManager, callback){
12091         el.update(response.responseText, updateManager.loadScripts, callback);
12092     }
12093 };
12094 /*
12095  * Based on:
12096  * Roo JS
12097  * (c)) Alan Knowles
12098  * Licence : LGPL
12099  */
12100
12101
12102 /**
12103  * @class Roo.DomTemplate
12104  * @extends Roo.Template
12105  * An effort at a dom based template engine..
12106  *
12107  * Similar to XTemplate, except it uses dom parsing to create the template..
12108  *
12109  * Supported features:
12110  *
12111  *  Tags:
12112
12113 <pre><code>
12114       {a_variable} - output encoded.
12115       {a_variable.format:("Y-m-d")} - call a method on the variable
12116       {a_variable:raw} - unencoded output
12117       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12118       {a_variable:this.method_on_template(...)} - call a method on the template object.
12119  
12120 </code></pre>
12121  *  The tpl tag:
12122 <pre><code>
12123         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12124         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12125         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12126         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12127   
12128 </code></pre>
12129  *      
12130  */
12131 Roo.DomTemplate = function()
12132 {
12133      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12134      if (this.html) {
12135         this.compile();
12136      }
12137 };
12138
12139
12140 Roo.extend(Roo.DomTemplate, Roo.Template, {
12141     /**
12142      * id counter for sub templates.
12143      */
12144     id : 0,
12145     /**
12146      * flag to indicate if dom parser is inside a pre,
12147      * it will strip whitespace if not.
12148      */
12149     inPre : false,
12150     
12151     /**
12152      * The various sub templates
12153      */
12154     tpls : false,
12155     
12156     
12157     
12158     /**
12159      *
12160      * basic tag replacing syntax
12161      * WORD:WORD()
12162      *
12163      * // you can fake an object call by doing this
12164      *  x.t:(test,tesT) 
12165      * 
12166      */
12167     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12168     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12169     
12170     iterChild : function (node, method) {
12171         
12172         var oldPre = this.inPre;
12173         if (node.tagName == 'PRE') {
12174             this.inPre = true;
12175         }
12176         for( var i = 0; i < node.childNodes.length; i++) {
12177             method.call(this, node.childNodes[i]);
12178         }
12179         this.inPre = oldPre;
12180     },
12181     
12182     
12183     
12184     /**
12185      * compile the template
12186      *
12187      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12188      *
12189      */
12190     compile: function()
12191     {
12192         var s = this.html;
12193         
12194         // covert the html into DOM...
12195         var doc = false;
12196         var div =false;
12197         try {
12198             doc = document.implementation.createHTMLDocument("");
12199             doc.documentElement.innerHTML =   this.html  ;
12200             div = doc.documentElement;
12201         } catch (e) {
12202             // old IE... - nasty -- it causes all sorts of issues.. with
12203             // images getting pulled from server..
12204             div = document.createElement('div');
12205             div.innerHTML = this.html;
12206         }
12207         //doc.documentElement.innerHTML = htmlBody
12208          
12209         
12210         
12211         this.tpls = [];
12212         var _t = this;
12213         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12214         
12215         var tpls = this.tpls;
12216         
12217         // create a top level template from the snippet..
12218         
12219         //Roo.log(div.innerHTML);
12220         
12221         var tpl = {
12222             uid : 'master',
12223             id : this.id++,
12224             attr : false,
12225             value : false,
12226             body : div.innerHTML,
12227             
12228             forCall : false,
12229             execCall : false,
12230             dom : div,
12231             isTop : true
12232             
12233         };
12234         tpls.unshift(tpl);
12235         
12236         
12237         // compile them...
12238         this.tpls = [];
12239         Roo.each(tpls, function(tp){
12240             this.compileTpl(tp);
12241             this.tpls[tp.id] = tp;
12242         }, this);
12243         
12244         this.master = tpls[0];
12245         return this;
12246         
12247         
12248     },
12249     
12250     compileNode : function(node, istop) {
12251         // test for
12252         //Roo.log(node);
12253         
12254         
12255         // skip anything not a tag..
12256         if (node.nodeType != 1) {
12257             if (node.nodeType == 3 && !this.inPre) {
12258                 // reduce white space..
12259                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12260                 
12261             }
12262             return;
12263         }
12264         
12265         var tpl = {
12266             uid : false,
12267             id : false,
12268             attr : false,
12269             value : false,
12270             body : '',
12271             
12272             forCall : false,
12273             execCall : false,
12274             dom : false,
12275             isTop : istop
12276             
12277             
12278         };
12279         
12280         
12281         switch(true) {
12282             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12283             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12284             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12285             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12286             // no default..
12287         }
12288         
12289         
12290         if (!tpl.attr) {
12291             // just itterate children..
12292             this.iterChild(node,this.compileNode);
12293             return;
12294         }
12295         tpl.uid = this.id++;
12296         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12297         node.removeAttribute('roo-'+ tpl.attr);
12298         if (tpl.attr != 'name') {
12299             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12300             node.parentNode.replaceChild(placeholder,  node);
12301         } else {
12302             
12303             var placeholder =  document.createElement('span');
12304             placeholder.className = 'roo-tpl-' + tpl.value;
12305             node.parentNode.replaceChild(placeholder,  node);
12306         }
12307         
12308         // parent now sees '{domtplXXXX}
12309         this.iterChild(node,this.compileNode);
12310         
12311         // we should now have node body...
12312         var div = document.createElement('div');
12313         div.appendChild(node);
12314         tpl.dom = node;
12315         // this has the unfortunate side effect of converting tagged attributes
12316         // eg. href="{...}" into %7C...%7D
12317         // this has been fixed by searching for those combo's although it's a bit hacky..
12318         
12319         
12320         tpl.body = div.innerHTML;
12321         
12322         
12323          
12324         tpl.id = tpl.uid;
12325         switch(tpl.attr) {
12326             case 'for' :
12327                 switch (tpl.value) {
12328                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12329                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12330                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12331                 }
12332                 break;
12333             
12334             case 'exec':
12335                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12336                 break;
12337             
12338             case 'if':     
12339                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12340                 break;
12341             
12342             case 'name':
12343                 tpl.id  = tpl.value; // replace non characters???
12344                 break;
12345             
12346         }
12347         
12348         
12349         this.tpls.push(tpl);
12350         
12351         
12352         
12353     },
12354     
12355     
12356     
12357     
12358     /**
12359      * Compile a segment of the template into a 'sub-template'
12360      *
12361      * 
12362      * 
12363      *
12364      */
12365     compileTpl : function(tpl)
12366     {
12367         var fm = Roo.util.Format;
12368         var useF = this.disableFormats !== true;
12369         
12370         var sep = Roo.isGecko ? "+\n" : ",\n";
12371         
12372         var undef = function(str) {
12373             Roo.debug && Roo.log("Property not found :"  + str);
12374             return '';
12375         };
12376           
12377         //Roo.log(tpl.body);
12378         
12379         
12380         
12381         var fn = function(m, lbrace, name, format, args)
12382         {
12383             //Roo.log("ARGS");
12384             //Roo.log(arguments);
12385             args = args ? args.replace(/\\'/g,"'") : args;
12386             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12387             if (typeof(format) == 'undefined') {
12388                 format =  'htmlEncode'; 
12389             }
12390             if (format == 'raw' ) {
12391                 format = false;
12392             }
12393             
12394             if(name.substr(0, 6) == 'domtpl'){
12395                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12396             }
12397             
12398             // build an array of options to determine if value is undefined..
12399             
12400             // basically get 'xxxx.yyyy' then do
12401             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12402             //    (function () { Roo.log("Property not found"); return ''; })() :
12403             //    ......
12404             
12405             var udef_ar = [];
12406             var lookfor = '';
12407             Roo.each(name.split('.'), function(st) {
12408                 lookfor += (lookfor.length ? '.': '') + st;
12409                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12410             });
12411             
12412             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12413             
12414             
12415             if(format && useF){
12416                 
12417                 args = args ? ',' + args : "";
12418                  
12419                 if(format.substr(0, 5) != "this."){
12420                     format = "fm." + format + '(';
12421                 }else{
12422                     format = 'this.call("'+ format.substr(5) + '", ';
12423                     args = ", values";
12424                 }
12425                 
12426                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12427             }
12428              
12429             if (args && args.length) {
12430                 // called with xxyx.yuu:(test,test)
12431                 // change to ()
12432                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12433             }
12434             // raw.. - :raw modifier..
12435             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12436             
12437         };
12438         var body;
12439         // branched to use + in gecko and [].join() in others
12440         if(Roo.isGecko){
12441             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12442                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12443                     "';};};";
12444         }else{
12445             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12446             body.push(tpl.body.replace(/(\r\n|\n)/g,
12447                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12448             body.push("'].join('');};};");
12449             body = body.join('');
12450         }
12451         
12452         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12453        
12454         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12455         eval(body);
12456         
12457         return this;
12458     },
12459      
12460     /**
12461      * same as applyTemplate, except it's done to one of the subTemplates
12462      * when using named templates, you can do:
12463      *
12464      * var str = pl.applySubTemplate('your-name', values);
12465      *
12466      * 
12467      * @param {Number} id of the template
12468      * @param {Object} values to apply to template
12469      * @param {Object} parent (normaly the instance of this object)
12470      */
12471     applySubTemplate : function(id, values, parent)
12472     {
12473         
12474         
12475         var t = this.tpls[id];
12476         
12477         
12478         try { 
12479             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12480                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12481                 return '';
12482             }
12483         } catch(e) {
12484             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12485             Roo.log(values);
12486           
12487             return '';
12488         }
12489         try { 
12490             
12491             if(t.execCall && t.execCall.call(this, values, parent)){
12492                 return '';
12493             }
12494         } catch(e) {
12495             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12496             Roo.log(values);
12497             return '';
12498         }
12499         
12500         try {
12501             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12502             parent = t.target ? values : parent;
12503             if(t.forCall && vs instanceof Array){
12504                 var buf = [];
12505                 for(var i = 0, len = vs.length; i < len; i++){
12506                     try {
12507                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12508                     } catch (e) {
12509                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12510                         Roo.log(e.body);
12511                         //Roo.log(t.compiled);
12512                         Roo.log(vs[i]);
12513                     }   
12514                 }
12515                 return buf.join('');
12516             }
12517         } catch (e) {
12518             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12519             Roo.log(values);
12520             return '';
12521         }
12522         try {
12523             return t.compiled.call(this, vs, parent);
12524         } catch (e) {
12525             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12526             Roo.log(e.body);
12527             //Roo.log(t.compiled);
12528             Roo.log(values);
12529             return '';
12530         }
12531     },
12532
12533    
12534
12535     applyTemplate : function(values){
12536         return this.master.compiled.call(this, values, {});
12537         //var s = this.subs;
12538     },
12539
12540     apply : function(){
12541         return this.applyTemplate.apply(this, arguments);
12542     }
12543
12544  });
12545
12546 Roo.DomTemplate.from = function(el){
12547     el = Roo.getDom(el);
12548     return new Roo.Domtemplate(el.value || el.innerHTML);
12549 };/*
12550  * Based on:
12551  * Ext JS Library 1.1.1
12552  * Copyright(c) 2006-2007, Ext JS, LLC.
12553  *
12554  * Originally Released Under LGPL - original licence link has changed is not relivant.
12555  *
12556  * Fork - LGPL
12557  * <script type="text/javascript">
12558  */
12559
12560 /**
12561  * @class Roo.util.DelayedTask
12562  * Provides a convenient method of performing setTimeout where a new
12563  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12564  * You can use this class to buffer
12565  * the keypress events for a certain number of milliseconds, and perform only if they stop
12566  * for that amount of time.
12567  * @constructor The parameters to this constructor serve as defaults and are not required.
12568  * @param {Function} fn (optional) The default function to timeout
12569  * @param {Object} scope (optional) The default scope of that timeout
12570  * @param {Array} args (optional) The default Array of arguments
12571  */
12572 Roo.util.DelayedTask = function(fn, scope, args){
12573     var id = null, d, t;
12574
12575     var call = function(){
12576         var now = new Date().getTime();
12577         if(now - t >= d){
12578             clearInterval(id);
12579             id = null;
12580             fn.apply(scope, args || []);
12581         }
12582     };
12583     /**
12584      * Cancels any pending timeout and queues a new one
12585      * @param {Number} delay The milliseconds to delay
12586      * @param {Function} newFn (optional) Overrides function passed to constructor
12587      * @param {Object} newScope (optional) Overrides scope passed to constructor
12588      * @param {Array} newArgs (optional) Overrides args passed to constructor
12589      */
12590     this.delay = function(delay, newFn, newScope, newArgs){
12591         if(id && delay != d){
12592             this.cancel();
12593         }
12594         d = delay;
12595         t = new Date().getTime();
12596         fn = newFn || fn;
12597         scope = newScope || scope;
12598         args = newArgs || args;
12599         if(!id){
12600             id = setInterval(call, d);
12601         }
12602     };
12603
12604     /**
12605      * Cancel the last queued timeout
12606      */
12607     this.cancel = function(){
12608         if(id){
12609             clearInterval(id);
12610             id = null;
12611         }
12612     };
12613 };/*
12614  * Based on:
12615  * Ext JS Library 1.1.1
12616  * Copyright(c) 2006-2007, Ext JS, LLC.
12617  *
12618  * Originally Released Under LGPL - original licence link has changed is not relivant.
12619  *
12620  * Fork - LGPL
12621  * <script type="text/javascript">
12622  */
12623  
12624  
12625 Roo.util.TaskRunner = function(interval){
12626     interval = interval || 10;
12627     var tasks = [], removeQueue = [];
12628     var id = 0;
12629     var running = false;
12630
12631     var stopThread = function(){
12632         running = false;
12633         clearInterval(id);
12634         id = 0;
12635     };
12636
12637     var startThread = function(){
12638         if(!running){
12639             running = true;
12640             id = setInterval(runTasks, interval);
12641         }
12642     };
12643
12644     var removeTask = function(task){
12645         removeQueue.push(task);
12646         if(task.onStop){
12647             task.onStop();
12648         }
12649     };
12650
12651     var runTasks = function(){
12652         if(removeQueue.length > 0){
12653             for(var i = 0, len = removeQueue.length; i < len; i++){
12654                 tasks.remove(removeQueue[i]);
12655             }
12656             removeQueue = [];
12657             if(tasks.length < 1){
12658                 stopThread();
12659                 return;
12660             }
12661         }
12662         var now = new Date().getTime();
12663         for(var i = 0, len = tasks.length; i < len; ++i){
12664             var t = tasks[i];
12665             var itime = now - t.taskRunTime;
12666             if(t.interval <= itime){
12667                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12668                 t.taskRunTime = now;
12669                 if(rt === false || t.taskRunCount === t.repeat){
12670                     removeTask(t);
12671                     return;
12672                 }
12673             }
12674             if(t.duration && t.duration <= (now - t.taskStartTime)){
12675                 removeTask(t);
12676             }
12677         }
12678     };
12679
12680     /**
12681      * Queues a new task.
12682      * @param {Object} task
12683      */
12684     this.start = function(task){
12685         tasks.push(task);
12686         task.taskStartTime = new Date().getTime();
12687         task.taskRunTime = 0;
12688         task.taskRunCount = 0;
12689         startThread();
12690         return task;
12691     };
12692
12693     this.stop = function(task){
12694         removeTask(task);
12695         return task;
12696     };
12697
12698     this.stopAll = function(){
12699         stopThread();
12700         for(var i = 0, len = tasks.length; i < len; i++){
12701             if(tasks[i].onStop){
12702                 tasks[i].onStop();
12703             }
12704         }
12705         tasks = [];
12706         removeQueue = [];
12707     };
12708 };
12709
12710 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12711  * Based on:
12712  * Ext JS Library 1.1.1
12713  * Copyright(c) 2006-2007, Ext JS, LLC.
12714  *
12715  * Originally Released Under LGPL - original licence link has changed is not relivant.
12716  *
12717  * Fork - LGPL
12718  * <script type="text/javascript">
12719  */
12720
12721  
12722 /**
12723  * @class Roo.util.MixedCollection
12724  * @extends Roo.util.Observable
12725  * A Collection class that maintains both numeric indexes and keys and exposes events.
12726  * @constructor
12727  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12728  * collection (defaults to false)
12729  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12730  * and return the key value for that item.  This is used when available to look up the key on items that
12731  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12732  * equivalent to providing an implementation for the {@link #getKey} method.
12733  */
12734 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12735     this.items = [];
12736     this.map = {};
12737     this.keys = [];
12738     this.length = 0;
12739     this.addEvents({
12740         /**
12741          * @event clear
12742          * Fires when the collection is cleared.
12743          */
12744         "clear" : true,
12745         /**
12746          * @event add
12747          * Fires when an item is added to the collection.
12748          * @param {Number} index The index at which the item was added.
12749          * @param {Object} o The item added.
12750          * @param {String} key The key associated with the added item.
12751          */
12752         "add" : true,
12753         /**
12754          * @event replace
12755          * Fires when an item is replaced in the collection.
12756          * @param {String} key he key associated with the new added.
12757          * @param {Object} old The item being replaced.
12758          * @param {Object} new The new item.
12759          */
12760         "replace" : true,
12761         /**
12762          * @event remove
12763          * Fires when an item is removed from the collection.
12764          * @param {Object} o The item being removed.
12765          * @param {String} key (optional) The key associated with the removed item.
12766          */
12767         "remove" : true,
12768         "sort" : true
12769     });
12770     this.allowFunctions = allowFunctions === true;
12771     if(keyFn){
12772         this.getKey = keyFn;
12773     }
12774     Roo.util.MixedCollection.superclass.constructor.call(this);
12775 };
12776
12777 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12778     allowFunctions : false,
12779     
12780 /**
12781  * Adds an item to the collection.
12782  * @param {String} key The key to associate with the item
12783  * @param {Object} o The item to add.
12784  * @return {Object} The item added.
12785  */
12786     add : function(key, o){
12787         if(arguments.length == 1){
12788             o = arguments[0];
12789             key = this.getKey(o);
12790         }
12791         if(typeof key == "undefined" || key === null){
12792             this.length++;
12793             this.items.push(o);
12794             this.keys.push(null);
12795         }else{
12796             var old = this.map[key];
12797             if(old){
12798                 return this.replace(key, o);
12799             }
12800             this.length++;
12801             this.items.push(o);
12802             this.map[key] = o;
12803             this.keys.push(key);
12804         }
12805         this.fireEvent("add", this.length-1, o, key);
12806         return o;
12807     },
12808        
12809 /**
12810   * MixedCollection has a generic way to fetch keys if you implement getKey.
12811 <pre><code>
12812 // normal way
12813 var mc = new Roo.util.MixedCollection();
12814 mc.add(someEl.dom.id, someEl);
12815 mc.add(otherEl.dom.id, otherEl);
12816 //and so on
12817
12818 // using getKey
12819 var mc = new Roo.util.MixedCollection();
12820 mc.getKey = function(el){
12821    return el.dom.id;
12822 };
12823 mc.add(someEl);
12824 mc.add(otherEl);
12825
12826 // or via the constructor
12827 var mc = new Roo.util.MixedCollection(false, function(el){
12828    return el.dom.id;
12829 });
12830 mc.add(someEl);
12831 mc.add(otherEl);
12832 </code></pre>
12833  * @param o {Object} The item for which to find the key.
12834  * @return {Object} The key for the passed item.
12835  */
12836     getKey : function(o){
12837          return o.id; 
12838     },
12839    
12840 /**
12841  * Replaces an item in the collection.
12842  * @param {String} key The key associated with the item to replace, or the item to replace.
12843  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12844  * @return {Object}  The new item.
12845  */
12846     replace : function(key, o){
12847         if(arguments.length == 1){
12848             o = arguments[0];
12849             key = this.getKey(o);
12850         }
12851         var old = this.item(key);
12852         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12853              return this.add(key, o);
12854         }
12855         var index = this.indexOfKey(key);
12856         this.items[index] = o;
12857         this.map[key] = o;
12858         this.fireEvent("replace", key, old, o);
12859         return o;
12860     },
12861    
12862 /**
12863  * Adds all elements of an Array or an Object to the collection.
12864  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12865  * an Array of values, each of which are added to the collection.
12866  */
12867     addAll : function(objs){
12868         if(arguments.length > 1 || objs instanceof Array){
12869             var args = arguments.length > 1 ? arguments : objs;
12870             for(var i = 0, len = args.length; i < len; i++){
12871                 this.add(args[i]);
12872             }
12873         }else{
12874             for(var key in objs){
12875                 if(this.allowFunctions || typeof objs[key] != "function"){
12876                     this.add(key, objs[key]);
12877                 }
12878             }
12879         }
12880     },
12881    
12882 /**
12883  * Executes the specified function once for every item in the collection, passing each
12884  * item as the first and only parameter. returning false from the function will stop the iteration.
12885  * @param {Function} fn The function to execute for each item.
12886  * @param {Object} scope (optional) The scope in which to execute the function.
12887  */
12888     each : function(fn, scope){
12889         var items = [].concat(this.items); // each safe for removal
12890         for(var i = 0, len = items.length; i < len; i++){
12891             if(fn.call(scope || items[i], items[i], i, len) === false){
12892                 break;
12893             }
12894         }
12895     },
12896    
12897 /**
12898  * Executes the specified function once for every key in the collection, passing each
12899  * key, and its associated item as the first two parameters.
12900  * @param {Function} fn The function to execute for each item.
12901  * @param {Object} scope (optional) The scope in which to execute the function.
12902  */
12903     eachKey : function(fn, scope){
12904         for(var i = 0, len = this.keys.length; i < len; i++){
12905             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12906         }
12907     },
12908    
12909 /**
12910  * Returns the first item in the collection which elicits a true return value from the
12911  * passed selection function.
12912  * @param {Function} fn The selection function to execute for each item.
12913  * @param {Object} scope (optional) The scope in which to execute the function.
12914  * @return {Object} The first item in the collection which returned true from the selection function.
12915  */
12916     find : function(fn, scope){
12917         for(var i = 0, len = this.items.length; i < len; i++){
12918             if(fn.call(scope || window, this.items[i], this.keys[i])){
12919                 return this.items[i];
12920             }
12921         }
12922         return null;
12923     },
12924    
12925 /**
12926  * Inserts an item at the specified index in the collection.
12927  * @param {Number} index The index to insert the item at.
12928  * @param {String} key The key to associate with the new item, or the item itself.
12929  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12930  * @return {Object} The item inserted.
12931  */
12932     insert : function(index, key, o){
12933         if(arguments.length == 2){
12934             o = arguments[1];
12935             key = this.getKey(o);
12936         }
12937         if(index >= this.length){
12938             return this.add(key, o);
12939         }
12940         this.length++;
12941         this.items.splice(index, 0, o);
12942         if(typeof key != "undefined" && key != null){
12943             this.map[key] = o;
12944         }
12945         this.keys.splice(index, 0, key);
12946         this.fireEvent("add", index, o, key);
12947         return o;
12948     },
12949    
12950 /**
12951  * Removed an item from the collection.
12952  * @param {Object} o The item to remove.
12953  * @return {Object} The item removed.
12954  */
12955     remove : function(o){
12956         return this.removeAt(this.indexOf(o));
12957     },
12958    
12959 /**
12960  * Remove an item from a specified index in the collection.
12961  * @param {Number} index The index within the collection of the item to remove.
12962  */
12963     removeAt : function(index){
12964         if(index < this.length && index >= 0){
12965             this.length--;
12966             var o = this.items[index];
12967             this.items.splice(index, 1);
12968             var key = this.keys[index];
12969             if(typeof key != "undefined"){
12970                 delete this.map[key];
12971             }
12972             this.keys.splice(index, 1);
12973             this.fireEvent("remove", o, key);
12974         }
12975     },
12976    
12977 /**
12978  * Removed an item associated with the passed key fom the collection.
12979  * @param {String} key The key of the item to remove.
12980  */
12981     removeKey : function(key){
12982         return this.removeAt(this.indexOfKey(key));
12983     },
12984    
12985 /**
12986  * Returns the number of items in the collection.
12987  * @return {Number} the number of items in the collection.
12988  */
12989     getCount : function(){
12990         return this.length; 
12991     },
12992    
12993 /**
12994  * Returns index within the collection of the passed Object.
12995  * @param {Object} o The item to find the index of.
12996  * @return {Number} index of the item.
12997  */
12998     indexOf : function(o){
12999         if(!this.items.indexOf){
13000             for(var i = 0, len = this.items.length; i < len; i++){
13001                 if(this.items[i] == o) return i;
13002             }
13003             return -1;
13004         }else{
13005             return this.items.indexOf(o);
13006         }
13007     },
13008    
13009 /**
13010  * Returns index within the collection of the passed key.
13011  * @param {String} key The key to find the index of.
13012  * @return {Number} index of the key.
13013  */
13014     indexOfKey : function(key){
13015         if(!this.keys.indexOf){
13016             for(var i = 0, len = this.keys.length; i < len; i++){
13017                 if(this.keys[i] == key) return i;
13018             }
13019             return -1;
13020         }else{
13021             return this.keys.indexOf(key);
13022         }
13023     },
13024    
13025 /**
13026  * Returns the item associated with the passed key OR index. Key has priority over index.
13027  * @param {String/Number} key The key or index of the item.
13028  * @return {Object} The item associated with the passed key.
13029  */
13030     item : function(key){
13031         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13032         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13033     },
13034     
13035 /**
13036  * Returns the item at the specified index.
13037  * @param {Number} index The index of the item.
13038  * @return {Object}
13039  */
13040     itemAt : function(index){
13041         return this.items[index];
13042     },
13043     
13044 /**
13045  * Returns the item associated with the passed key.
13046  * @param {String/Number} key The key of the item.
13047  * @return {Object} The item associated with the passed key.
13048  */
13049     key : function(key){
13050         return this.map[key];
13051     },
13052    
13053 /**
13054  * Returns true if the collection contains the passed Object as an item.
13055  * @param {Object} o  The Object to look for in the collection.
13056  * @return {Boolean} True if the collection contains the Object as an item.
13057  */
13058     contains : function(o){
13059         return this.indexOf(o) != -1;
13060     },
13061    
13062 /**
13063  * Returns true if the collection contains the passed Object as a key.
13064  * @param {String} key The key to look for in the collection.
13065  * @return {Boolean} True if the collection contains the Object as a key.
13066  */
13067     containsKey : function(key){
13068         return typeof this.map[key] != "undefined";
13069     },
13070    
13071 /**
13072  * Removes all items from the collection.
13073  */
13074     clear : function(){
13075         this.length = 0;
13076         this.items = [];
13077         this.keys = [];
13078         this.map = {};
13079         this.fireEvent("clear");
13080     },
13081    
13082 /**
13083  * Returns the first item in the collection.
13084  * @return {Object} the first item in the collection..
13085  */
13086     first : function(){
13087         return this.items[0]; 
13088     },
13089    
13090 /**
13091  * Returns the last item in the collection.
13092  * @return {Object} the last item in the collection..
13093  */
13094     last : function(){
13095         return this.items[this.length-1];   
13096     },
13097     
13098     _sort : function(property, dir, fn){
13099         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13100         fn = fn || function(a, b){
13101             return a-b;
13102         };
13103         var c = [], k = this.keys, items = this.items;
13104         for(var i = 0, len = items.length; i < len; i++){
13105             c[c.length] = {key: k[i], value: items[i], index: i};
13106         }
13107         c.sort(function(a, b){
13108             var v = fn(a[property], b[property]) * dsc;
13109             if(v == 0){
13110                 v = (a.index < b.index ? -1 : 1);
13111             }
13112             return v;
13113         });
13114         for(var i = 0, len = c.length; i < len; i++){
13115             items[i] = c[i].value;
13116             k[i] = c[i].key;
13117         }
13118         this.fireEvent("sort", this);
13119     },
13120     
13121     /**
13122      * Sorts this collection with the passed comparison function
13123      * @param {String} direction (optional) "ASC" or "DESC"
13124      * @param {Function} fn (optional) comparison function
13125      */
13126     sort : function(dir, fn){
13127         this._sort("value", dir, fn);
13128     },
13129     
13130     /**
13131      * Sorts this collection by keys
13132      * @param {String} direction (optional) "ASC" or "DESC"
13133      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13134      */
13135     keySort : function(dir, fn){
13136         this._sort("key", dir, fn || function(a, b){
13137             return String(a).toUpperCase()-String(b).toUpperCase();
13138         });
13139     },
13140     
13141     /**
13142      * Returns a range of items in this collection
13143      * @param {Number} startIndex (optional) defaults to 0
13144      * @param {Number} endIndex (optional) default to the last item
13145      * @return {Array} An array of items
13146      */
13147     getRange : function(start, end){
13148         var items = this.items;
13149         if(items.length < 1){
13150             return [];
13151         }
13152         start = start || 0;
13153         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13154         var r = [];
13155         if(start <= end){
13156             for(var i = start; i <= end; i++) {
13157                     r[r.length] = items[i];
13158             }
13159         }else{
13160             for(var i = start; i >= end; i--) {
13161                     r[r.length] = items[i];
13162             }
13163         }
13164         return r;
13165     },
13166         
13167     /**
13168      * Filter the <i>objects</i> in this collection by a specific property. 
13169      * Returns a new collection that has been filtered.
13170      * @param {String} property A property on your objects
13171      * @param {String/RegExp} value Either string that the property values 
13172      * should start with or a RegExp to test against the property
13173      * @return {MixedCollection} The new filtered collection
13174      */
13175     filter : function(property, value){
13176         if(!value.exec){ // not a regex
13177             value = String(value);
13178             if(value.length == 0){
13179                 return this.clone();
13180             }
13181             value = new RegExp("^" + Roo.escapeRe(value), "i");
13182         }
13183         return this.filterBy(function(o){
13184             return o && value.test(o[property]);
13185         });
13186         },
13187     
13188     /**
13189      * Filter by a function. * Returns a new collection that has been filtered.
13190      * The passed function will be called with each 
13191      * object in the collection. If the function returns true, the value is included 
13192      * otherwise it is filtered.
13193      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13194      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13195      * @return {MixedCollection} The new filtered collection
13196      */
13197     filterBy : function(fn, scope){
13198         var r = new Roo.util.MixedCollection();
13199         r.getKey = this.getKey;
13200         var k = this.keys, it = this.items;
13201         for(var i = 0, len = it.length; i < len; i++){
13202             if(fn.call(scope||this, it[i], k[i])){
13203                                 r.add(k[i], it[i]);
13204                         }
13205         }
13206         return r;
13207     },
13208     
13209     /**
13210      * Creates a duplicate of this collection
13211      * @return {MixedCollection}
13212      */
13213     clone : function(){
13214         var r = new Roo.util.MixedCollection();
13215         var k = this.keys, it = this.items;
13216         for(var i = 0, len = it.length; i < len; i++){
13217             r.add(k[i], it[i]);
13218         }
13219         r.getKey = this.getKey;
13220         return r;
13221     }
13222 });
13223 /**
13224  * Returns the item associated with the passed key or index.
13225  * @method
13226  * @param {String/Number} key The key or index of the item.
13227  * @return {Object} The item associated with the passed key.
13228  */
13229 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13230  * Based on:
13231  * Ext JS Library 1.1.1
13232  * Copyright(c) 2006-2007, Ext JS, LLC.
13233  *
13234  * Originally Released Under LGPL - original licence link has changed is not relivant.
13235  *
13236  * Fork - LGPL
13237  * <script type="text/javascript">
13238  */
13239 /**
13240  * @class Roo.util.JSON
13241  * Modified version of Douglas Crockford"s json.js that doesn"t
13242  * mess with the Object prototype 
13243  * http://www.json.org/js.html
13244  * @singleton
13245  */
13246 Roo.util.JSON = new (function(){
13247     var useHasOwn = {}.hasOwnProperty ? true : false;
13248     
13249     // crashes Safari in some instances
13250     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13251     
13252     var pad = function(n) {
13253         return n < 10 ? "0" + n : n;
13254     };
13255     
13256     var m = {
13257         "\b": '\\b',
13258         "\t": '\\t',
13259         "\n": '\\n',
13260         "\f": '\\f',
13261         "\r": '\\r',
13262         '"' : '\\"',
13263         "\\": '\\\\'
13264     };
13265
13266     var encodeString = function(s){
13267         if (/["\\\x00-\x1f]/.test(s)) {
13268             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13269                 var c = m[b];
13270                 if(c){
13271                     return c;
13272                 }
13273                 c = b.charCodeAt();
13274                 return "\\u00" +
13275                     Math.floor(c / 16).toString(16) +
13276                     (c % 16).toString(16);
13277             }) + '"';
13278         }
13279         return '"' + s + '"';
13280     };
13281     
13282     var encodeArray = function(o){
13283         var a = ["["], b, i, l = o.length, v;
13284             for (i = 0; i < l; i += 1) {
13285                 v = o[i];
13286                 switch (typeof v) {
13287                     case "undefined":
13288                     case "function":
13289                     case "unknown":
13290                         break;
13291                     default:
13292                         if (b) {
13293                             a.push(',');
13294                         }
13295                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13296                         b = true;
13297                 }
13298             }
13299             a.push("]");
13300             return a.join("");
13301     };
13302     
13303     var encodeDate = function(o){
13304         return '"' + o.getFullYear() + "-" +
13305                 pad(o.getMonth() + 1) + "-" +
13306                 pad(o.getDate()) + "T" +
13307                 pad(o.getHours()) + ":" +
13308                 pad(o.getMinutes()) + ":" +
13309                 pad(o.getSeconds()) + '"';
13310     };
13311     
13312     /**
13313      * Encodes an Object, Array or other value
13314      * @param {Mixed} o The variable to encode
13315      * @return {String} The JSON string
13316      */
13317     this.encode = function(o)
13318     {
13319         // should this be extended to fully wrap stringify..
13320         
13321         if(typeof o == "undefined" || o === null){
13322             return "null";
13323         }else if(o instanceof Array){
13324             return encodeArray(o);
13325         }else if(o instanceof Date){
13326             return encodeDate(o);
13327         }else if(typeof o == "string"){
13328             return encodeString(o);
13329         }else if(typeof o == "number"){
13330             return isFinite(o) ? String(o) : "null";
13331         }else if(typeof o == "boolean"){
13332             return String(o);
13333         }else {
13334             var a = ["{"], b, i, v;
13335             for (i in o) {
13336                 if(!useHasOwn || o.hasOwnProperty(i)) {
13337                     v = o[i];
13338                     switch (typeof v) {
13339                     case "undefined":
13340                     case "function":
13341                     case "unknown":
13342                         break;
13343                     default:
13344                         if(b){
13345                             a.push(',');
13346                         }
13347                         a.push(this.encode(i), ":",
13348                                 v === null ? "null" : this.encode(v));
13349                         b = true;
13350                     }
13351                 }
13352             }
13353             a.push("}");
13354             return a.join("");
13355         }
13356     };
13357     
13358     /**
13359      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13360      * @param {String} json The JSON string
13361      * @return {Object} The resulting object
13362      */
13363     this.decode = function(json){
13364         
13365         return  /** eval:var:json */ eval("(" + json + ')');
13366     };
13367 })();
13368 /** 
13369  * Shorthand for {@link Roo.util.JSON#encode}
13370  * @member Roo encode 
13371  * @method */
13372 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13373 /** 
13374  * Shorthand for {@link Roo.util.JSON#decode}
13375  * @member Roo decode 
13376  * @method */
13377 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13378 /*
13379  * Based on:
13380  * Ext JS Library 1.1.1
13381  * Copyright(c) 2006-2007, Ext JS, LLC.
13382  *
13383  * Originally Released Under LGPL - original licence link has changed is not relivant.
13384  *
13385  * Fork - LGPL
13386  * <script type="text/javascript">
13387  */
13388  
13389 /**
13390  * @class Roo.util.Format
13391  * Reusable data formatting functions
13392  * @singleton
13393  */
13394 Roo.util.Format = function(){
13395     var trimRe = /^\s+|\s+$/g;
13396     return {
13397         /**
13398          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13399          * @param {String} value The string to truncate
13400          * @param {Number} length The maximum length to allow before truncating
13401          * @return {String} The converted text
13402          */
13403         ellipsis : function(value, len){
13404             if(value && value.length > len){
13405                 return value.substr(0, len-3)+"...";
13406             }
13407             return value;
13408         },
13409
13410         /**
13411          * Checks a reference and converts it to empty string if it is undefined
13412          * @param {Mixed} value Reference to check
13413          * @return {Mixed} Empty string if converted, otherwise the original value
13414          */
13415         undef : function(value){
13416             return typeof value != "undefined" ? value : "";
13417         },
13418
13419         /**
13420          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13421          * @param {String} value The string to encode
13422          * @return {String} The encoded text
13423          */
13424         htmlEncode : function(value){
13425             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13426         },
13427
13428         /**
13429          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13430          * @param {String} value The string to decode
13431          * @return {String} The decoded text
13432          */
13433         htmlDecode : function(value){
13434             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13435         },
13436
13437         /**
13438          * Trims any whitespace from either side of a string
13439          * @param {String} value The text to trim
13440          * @return {String} The trimmed text
13441          */
13442         trim : function(value){
13443             return String(value).replace(trimRe, "");
13444         },
13445
13446         /**
13447          * Returns a substring from within an original string
13448          * @param {String} value The original text
13449          * @param {Number} start The start index of the substring
13450          * @param {Number} length The length of the substring
13451          * @return {String} The substring
13452          */
13453         substr : function(value, start, length){
13454             return String(value).substr(start, length);
13455         },
13456
13457         /**
13458          * Converts a string to all lower case letters
13459          * @param {String} value The text to convert
13460          * @return {String} The converted text
13461          */
13462         lowercase : function(value){
13463             return String(value).toLowerCase();
13464         },
13465
13466         /**
13467          * Converts a string to all upper case letters
13468          * @param {String} value The text to convert
13469          * @return {String} The converted text
13470          */
13471         uppercase : function(value){
13472             return String(value).toUpperCase();
13473         },
13474
13475         /**
13476          * Converts the first character only of a string to upper case
13477          * @param {String} value The text to convert
13478          * @return {String} The converted text
13479          */
13480         capitalize : function(value){
13481             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13482         },
13483
13484         // private
13485         call : function(value, fn){
13486             if(arguments.length > 2){
13487                 var args = Array.prototype.slice.call(arguments, 2);
13488                 args.unshift(value);
13489                  
13490                 return /** eval:var:value */  eval(fn).apply(window, args);
13491             }else{
13492                 /** eval:var:value */
13493                 return /** eval:var:value */ eval(fn).call(window, value);
13494             }
13495         },
13496
13497        
13498         /**
13499          * safer version of Math.toFixed..??/
13500          * @param {Number/String} value The numeric value to format
13501          * @param {Number/String} value Decimal places 
13502          * @return {String} The formatted currency string
13503          */
13504         toFixed : function(v, n)
13505         {
13506             // why not use to fixed - precision is buggered???
13507             if (!n) {
13508                 return Math.round(v-0);
13509             }
13510             var fact = Math.pow(10,n+1);
13511             v = (Math.round((v-0)*fact))/fact;
13512             var z = (''+fact).substring(2);
13513             if (v == Math.floor(v)) {
13514                 return Math.floor(v) + '.' + z;
13515             }
13516             
13517             // now just padd decimals..
13518             var ps = String(v).split('.');
13519             var fd = (ps[1] + z);
13520             var r = fd.substring(0,n); 
13521             var rm = fd.substring(n); 
13522             if (rm < 5) {
13523                 return ps[0] + '.' + r;
13524             }
13525             r*=1; // turn it into a number;
13526             r++;
13527             if (String(r).length != n) {
13528                 ps[0]*=1;
13529                 ps[0]++;
13530                 r = String(r).substring(1); // chop the end off.
13531             }
13532             
13533             return ps[0] + '.' + r;
13534              
13535         },
13536         
13537         /**
13538          * Format a number as US currency
13539          * @param {Number/String} value The numeric value to format
13540          * @return {String} The formatted currency string
13541          */
13542         usMoney : function(v){
13543             return '$' + Roo.util.Format.number(v);
13544         },
13545         
13546         /**
13547          * Format a number
13548          * eventually this should probably emulate php's number_format
13549          * @param {Number/String} value The numeric value to format
13550          * @param {Number} decimals number of decimal places
13551          * @return {String} The formatted currency string
13552          */
13553         number : function(v,decimals)
13554         {
13555             // multiply and round.
13556             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13557             var mul = Math.pow(10, decimals);
13558             var zero = String(mul).substring(1);
13559             v = (Math.round((v-0)*mul))/mul;
13560             
13561             // if it's '0' number.. then
13562             
13563             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13564             v = String(v);
13565             var ps = v.split('.');
13566             var whole = ps[0];
13567             
13568             
13569             var r = /(\d+)(\d{3})/;
13570             // add comma's
13571             while (r.test(whole)) {
13572                 whole = whole.replace(r, '$1' + ',' + '$2');
13573             }
13574             
13575             
13576             var sub = ps[1] ?
13577                     // has decimals..
13578                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13579                     // does not have decimals
13580                     (decimals ? ('.' + zero) : '');
13581             
13582             
13583             return whole + sub ;
13584         },
13585         
13586         /**
13587          * Parse a value into a formatted date using the specified format pattern.
13588          * @param {Mixed} value The value to format
13589          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13590          * @return {String} The formatted date string
13591          */
13592         date : function(v, format){
13593             if(!v){
13594                 return "";
13595             }
13596             if(!(v instanceof Date)){
13597                 v = new Date(Date.parse(v));
13598             }
13599             return v.dateFormat(format || "m/d/Y");
13600         },
13601
13602         /**
13603          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13604          * @param {String} format Any valid date format string
13605          * @return {Function} The date formatting function
13606          */
13607         dateRenderer : function(format){
13608             return function(v){
13609                 return Roo.util.Format.date(v, format);  
13610             };
13611         },
13612
13613         // private
13614         stripTagsRE : /<\/?[^>]+>/gi,
13615         
13616         /**
13617          * Strips all HTML tags
13618          * @param {Mixed} value The text from which to strip tags
13619          * @return {String} The stripped text
13620          */
13621         stripTags : function(v){
13622             return !v ? v : String(v).replace(this.stripTagsRE, "");
13623         }
13624     };
13625 }();/*
13626  * Based on:
13627  * Ext JS Library 1.1.1
13628  * Copyright(c) 2006-2007, Ext JS, LLC.
13629  *
13630  * Originally Released Under LGPL - original licence link has changed is not relivant.
13631  *
13632  * Fork - LGPL
13633  * <script type="text/javascript">
13634  */
13635
13636
13637  
13638
13639 /**
13640  * @class Roo.MasterTemplate
13641  * @extends Roo.Template
13642  * Provides a template that can have child templates. The syntax is:
13643 <pre><code>
13644 var t = new Roo.MasterTemplate(
13645         '&lt;select name="{name}"&gt;',
13646                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13647         '&lt;/select&gt;'
13648 );
13649 t.add('options', {value: 'foo', text: 'bar'});
13650 // or you can add multiple child elements in one shot
13651 t.addAll('options', [
13652     {value: 'foo', text: 'bar'},
13653     {value: 'foo2', text: 'bar2'},
13654     {value: 'foo3', text: 'bar3'}
13655 ]);
13656 // then append, applying the master template values
13657 t.append('my-form', {name: 'my-select'});
13658 </code></pre>
13659 * A name attribute for the child template is not required if you have only one child
13660 * template or you want to refer to them by index.
13661  */
13662 Roo.MasterTemplate = function(){
13663     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13664     this.originalHtml = this.html;
13665     var st = {};
13666     var m, re = this.subTemplateRe;
13667     re.lastIndex = 0;
13668     var subIndex = 0;
13669     while(m = re.exec(this.html)){
13670         var name = m[1], content = m[2];
13671         st[subIndex] = {
13672             name: name,
13673             index: subIndex,
13674             buffer: [],
13675             tpl : new Roo.Template(content)
13676         };
13677         if(name){
13678             st[name] = st[subIndex];
13679         }
13680         st[subIndex].tpl.compile();
13681         st[subIndex].tpl.call = this.call.createDelegate(this);
13682         subIndex++;
13683     }
13684     this.subCount = subIndex;
13685     this.subs = st;
13686 };
13687 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13688     /**
13689     * The regular expression used to match sub templates
13690     * @type RegExp
13691     * @property
13692     */
13693     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13694
13695     /**
13696      * Applies the passed values to a child template.
13697      * @param {String/Number} name (optional) The name or index of the child template
13698      * @param {Array/Object} values The values to be applied to the template
13699      * @return {MasterTemplate} this
13700      */
13701      add : function(name, values){
13702         if(arguments.length == 1){
13703             values = arguments[0];
13704             name = 0;
13705         }
13706         var s = this.subs[name];
13707         s.buffer[s.buffer.length] = s.tpl.apply(values);
13708         return this;
13709     },
13710
13711     /**
13712      * Applies all the passed values to a child template.
13713      * @param {String/Number} name (optional) The name or index of the child template
13714      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13715      * @param {Boolean} reset (optional) True to reset the template first
13716      * @return {MasterTemplate} this
13717      */
13718     fill : function(name, values, reset){
13719         var a = arguments;
13720         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13721             values = a[0];
13722             name = 0;
13723             reset = a[1];
13724         }
13725         if(reset){
13726             this.reset();
13727         }
13728         for(var i = 0, len = values.length; i < len; i++){
13729             this.add(name, values[i]);
13730         }
13731         return this;
13732     },
13733
13734     /**
13735      * Resets the template for reuse
13736      * @return {MasterTemplate} this
13737      */
13738      reset : function(){
13739         var s = this.subs;
13740         for(var i = 0; i < this.subCount; i++){
13741             s[i].buffer = [];
13742         }
13743         return this;
13744     },
13745
13746     applyTemplate : function(values){
13747         var s = this.subs;
13748         var replaceIndex = -1;
13749         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13750             return s[++replaceIndex].buffer.join("");
13751         });
13752         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13753     },
13754
13755     apply : function(){
13756         return this.applyTemplate.apply(this, arguments);
13757     },
13758
13759     compile : function(){return this;}
13760 });
13761
13762 /**
13763  * Alias for fill().
13764  * @method
13765  */
13766 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13767  /**
13768  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13769  * var tpl = Roo.MasterTemplate.from('element-id');
13770  * @param {String/HTMLElement} el
13771  * @param {Object} config
13772  * @static
13773  */
13774 Roo.MasterTemplate.from = function(el, config){
13775     el = Roo.getDom(el);
13776     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13777 };/*
13778  * Based on:
13779  * Ext JS Library 1.1.1
13780  * Copyright(c) 2006-2007, Ext JS, LLC.
13781  *
13782  * Originally Released Under LGPL - original licence link has changed is not relivant.
13783  *
13784  * Fork - LGPL
13785  * <script type="text/javascript">
13786  */
13787
13788  
13789 /**
13790  * @class Roo.util.CSS
13791  * Utility class for manipulating CSS rules
13792  * @singleton
13793  */
13794 Roo.util.CSS = function(){
13795         var rules = null;
13796         var doc = document;
13797
13798     var camelRe = /(-[a-z])/gi;
13799     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13800
13801    return {
13802    /**
13803     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13804     * tag and appended to the HEAD of the document.
13805     * @param {String|Object} cssText The text containing the css rules
13806     * @param {String} id An id to add to the stylesheet for later removal
13807     * @return {StyleSheet}
13808     */
13809     createStyleSheet : function(cssText, id){
13810         var ss;
13811         var head = doc.getElementsByTagName("head")[0];
13812         var nrules = doc.createElement("style");
13813         nrules.setAttribute("type", "text/css");
13814         if(id){
13815             nrules.setAttribute("id", id);
13816         }
13817         if (typeof(cssText) != 'string') {
13818             // support object maps..
13819             // not sure if this a good idea.. 
13820             // perhaps it should be merged with the general css handling
13821             // and handle js style props.
13822             var cssTextNew = [];
13823             for(var n in cssText) {
13824                 var citems = [];
13825                 for(var k in cssText[n]) {
13826                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13827                 }
13828                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13829                 
13830             }
13831             cssText = cssTextNew.join("\n");
13832             
13833         }
13834        
13835        
13836        if(Roo.isIE){
13837            head.appendChild(nrules);
13838            ss = nrules.styleSheet;
13839            ss.cssText = cssText;
13840        }else{
13841            try{
13842                 nrules.appendChild(doc.createTextNode(cssText));
13843            }catch(e){
13844                nrules.cssText = cssText; 
13845            }
13846            head.appendChild(nrules);
13847            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13848        }
13849        this.cacheStyleSheet(ss);
13850        return ss;
13851    },
13852
13853    /**
13854     * Removes a style or link tag by id
13855     * @param {String} id The id of the tag
13856     */
13857    removeStyleSheet : function(id){
13858        var existing = doc.getElementById(id);
13859        if(existing){
13860            existing.parentNode.removeChild(existing);
13861        }
13862    },
13863
13864    /**
13865     * Dynamically swaps an existing stylesheet reference for a new one
13866     * @param {String} id The id of an existing link tag to remove
13867     * @param {String} url The href of the new stylesheet to include
13868     */
13869    swapStyleSheet : function(id, url){
13870        this.removeStyleSheet(id);
13871        var ss = doc.createElement("link");
13872        ss.setAttribute("rel", "stylesheet");
13873        ss.setAttribute("type", "text/css");
13874        ss.setAttribute("id", id);
13875        ss.setAttribute("href", url);
13876        doc.getElementsByTagName("head")[0].appendChild(ss);
13877    },
13878    
13879    /**
13880     * Refresh the rule cache if you have dynamically added stylesheets
13881     * @return {Object} An object (hash) of rules indexed by selector
13882     */
13883    refreshCache : function(){
13884        return this.getRules(true);
13885    },
13886
13887    // private
13888    cacheStyleSheet : function(stylesheet){
13889        if(!rules){
13890            rules = {};
13891        }
13892        try{// try catch for cross domain access issue
13893            var ssRules = stylesheet.cssRules || stylesheet.rules;
13894            for(var j = ssRules.length-1; j >= 0; --j){
13895                rules[ssRules[j].selectorText] = ssRules[j];
13896            }
13897        }catch(e){}
13898    },
13899    
13900    /**
13901     * Gets all css rules for the document
13902     * @param {Boolean} refreshCache true to refresh the internal cache
13903     * @return {Object} An object (hash) of rules indexed by selector
13904     */
13905    getRules : function(refreshCache){
13906                 if(rules == null || refreshCache){
13907                         rules = {};
13908                         var ds = doc.styleSheets;
13909                         for(var i =0, len = ds.length; i < len; i++){
13910                             try{
13911                         this.cacheStyleSheet(ds[i]);
13912                     }catch(e){} 
13913                 }
13914                 }
13915                 return rules;
13916         },
13917         
13918         /**
13919     * Gets an an individual CSS rule by selector(s)
13920     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13921     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13922     * @return {CSSRule} The CSS rule or null if one is not found
13923     */
13924    getRule : function(selector, refreshCache){
13925                 var rs = this.getRules(refreshCache);
13926                 if(!(selector instanceof Array)){
13927                     return rs[selector];
13928                 }
13929                 for(var i = 0; i < selector.length; i++){
13930                         if(rs[selector[i]]){
13931                                 return rs[selector[i]];
13932                         }
13933                 }
13934                 return null;
13935         },
13936         
13937         
13938         /**
13939     * Updates a rule property
13940     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13941     * @param {String} property The css property
13942     * @param {String} value The new value for the property
13943     * @return {Boolean} true If a rule was found and updated
13944     */
13945    updateRule : function(selector, property, value){
13946                 if(!(selector instanceof Array)){
13947                         var rule = this.getRule(selector);
13948                         if(rule){
13949                                 rule.style[property.replace(camelRe, camelFn)] = value;
13950                                 return true;
13951                         }
13952                 }else{
13953                         for(var i = 0; i < selector.length; i++){
13954                                 if(this.updateRule(selector[i], property, value)){
13955                                         return true;
13956                                 }
13957                         }
13958                 }
13959                 return false;
13960         }
13961    };   
13962 }();/*
13963  * Based on:
13964  * Ext JS Library 1.1.1
13965  * Copyright(c) 2006-2007, Ext JS, LLC.
13966  *
13967  * Originally Released Under LGPL - original licence link has changed is not relivant.
13968  *
13969  * Fork - LGPL
13970  * <script type="text/javascript">
13971  */
13972
13973  
13974
13975 /**
13976  * @class Roo.util.ClickRepeater
13977  * @extends Roo.util.Observable
13978  * 
13979  * A wrapper class which can be applied to any element. Fires a "click" event while the
13980  * mouse is pressed. The interval between firings may be specified in the config but
13981  * defaults to 10 milliseconds.
13982  * 
13983  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13984  * 
13985  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13986  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13987  * Similar to an autorepeat key delay.
13988  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13989  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13990  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13991  *           "interval" and "delay" are ignored. "immediate" is honored.
13992  * @cfg {Boolean} preventDefault True to prevent the default click event
13993  * @cfg {Boolean} stopDefault True to stop the default click event
13994  * 
13995  * @history
13996  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13997  *     2007-02-02 jvs Renamed to ClickRepeater
13998  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13999  *
14000  *  @constructor
14001  * @param {String/HTMLElement/Element} el The element to listen on
14002  * @param {Object} config
14003  **/
14004 Roo.util.ClickRepeater = function(el, config)
14005 {
14006     this.el = Roo.get(el);
14007     this.el.unselectable();
14008
14009     Roo.apply(this, config);
14010
14011     this.addEvents({
14012     /**
14013      * @event mousedown
14014      * Fires when the mouse button is depressed.
14015      * @param {Roo.util.ClickRepeater} this
14016      */
14017         "mousedown" : true,
14018     /**
14019      * @event click
14020      * Fires on a specified interval during the time the element is pressed.
14021      * @param {Roo.util.ClickRepeater} this
14022      */
14023         "click" : true,
14024     /**
14025      * @event mouseup
14026      * Fires when the mouse key is released.
14027      * @param {Roo.util.ClickRepeater} this
14028      */
14029         "mouseup" : true
14030     });
14031
14032     this.el.on("mousedown", this.handleMouseDown, this);
14033     if(this.preventDefault || this.stopDefault){
14034         this.el.on("click", function(e){
14035             if(this.preventDefault){
14036                 e.preventDefault();
14037             }
14038             if(this.stopDefault){
14039                 e.stopEvent();
14040             }
14041         }, this);
14042     }
14043
14044     // allow inline handler
14045     if(this.handler){
14046         this.on("click", this.handler,  this.scope || this);
14047     }
14048
14049     Roo.util.ClickRepeater.superclass.constructor.call(this);
14050 };
14051
14052 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14053     interval : 20,
14054     delay: 250,
14055     preventDefault : true,
14056     stopDefault : false,
14057     timer : 0,
14058
14059     // private
14060     handleMouseDown : function(){
14061         clearTimeout(this.timer);
14062         this.el.blur();
14063         if(this.pressClass){
14064             this.el.addClass(this.pressClass);
14065         }
14066         this.mousedownTime = new Date();
14067
14068         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14069         this.el.on("mouseout", this.handleMouseOut, this);
14070
14071         this.fireEvent("mousedown", this);
14072         this.fireEvent("click", this);
14073         
14074         this.timer = this.click.defer(this.delay || this.interval, this);
14075     },
14076
14077     // private
14078     click : function(){
14079         this.fireEvent("click", this);
14080         this.timer = this.click.defer(this.getInterval(), this);
14081     },
14082
14083     // private
14084     getInterval: function(){
14085         if(!this.accelerate){
14086             return this.interval;
14087         }
14088         var pressTime = this.mousedownTime.getElapsed();
14089         if(pressTime < 500){
14090             return 400;
14091         }else if(pressTime < 1700){
14092             return 320;
14093         }else if(pressTime < 2600){
14094             return 250;
14095         }else if(pressTime < 3500){
14096             return 180;
14097         }else if(pressTime < 4400){
14098             return 140;
14099         }else if(pressTime < 5300){
14100             return 80;
14101         }else if(pressTime < 6200){
14102             return 50;
14103         }else{
14104             return 10;
14105         }
14106     },
14107
14108     // private
14109     handleMouseOut : function(){
14110         clearTimeout(this.timer);
14111         if(this.pressClass){
14112             this.el.removeClass(this.pressClass);
14113         }
14114         this.el.on("mouseover", this.handleMouseReturn, this);
14115     },
14116
14117     // private
14118     handleMouseReturn : function(){
14119         this.el.un("mouseover", this.handleMouseReturn);
14120         if(this.pressClass){
14121             this.el.addClass(this.pressClass);
14122         }
14123         this.click();
14124     },
14125
14126     // private
14127     handleMouseUp : function(){
14128         clearTimeout(this.timer);
14129         this.el.un("mouseover", this.handleMouseReturn);
14130         this.el.un("mouseout", this.handleMouseOut);
14131         Roo.get(document).un("mouseup", this.handleMouseUp);
14132         this.el.removeClass(this.pressClass);
14133         this.fireEvent("mouseup", this);
14134     }
14135 });/*
14136  * Based on:
14137  * Ext JS Library 1.1.1
14138  * Copyright(c) 2006-2007, Ext JS, LLC.
14139  *
14140  * Originally Released Under LGPL - original licence link has changed is not relivant.
14141  *
14142  * Fork - LGPL
14143  * <script type="text/javascript">
14144  */
14145
14146  
14147 /**
14148  * @class Roo.KeyNav
14149  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14150  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14151  * way to implement custom navigation schemes for any UI component.</p>
14152  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14153  * pageUp, pageDown, del, home, end.  Usage:</p>
14154  <pre><code>
14155 var nav = new Roo.KeyNav("my-element", {
14156     "left" : function(e){
14157         this.moveLeft(e.ctrlKey);
14158     },
14159     "right" : function(e){
14160         this.moveRight(e.ctrlKey);
14161     },
14162     "enter" : function(e){
14163         this.save();
14164     },
14165     scope : this
14166 });
14167 </code></pre>
14168  * @constructor
14169  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14170  * @param {Object} config The config
14171  */
14172 Roo.KeyNav = function(el, config){
14173     this.el = Roo.get(el);
14174     Roo.apply(this, config);
14175     if(!this.disabled){
14176         this.disabled = true;
14177         this.enable();
14178     }
14179 };
14180
14181 Roo.KeyNav.prototype = {
14182     /**
14183      * @cfg {Boolean} disabled
14184      * True to disable this KeyNav instance (defaults to false)
14185      */
14186     disabled : false,
14187     /**
14188      * @cfg {String} defaultEventAction
14189      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14190      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14191      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14192      */
14193     defaultEventAction: "stopEvent",
14194     /**
14195      * @cfg {Boolean} forceKeyDown
14196      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14197      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14198      * handle keydown instead of keypress.
14199      */
14200     forceKeyDown : false,
14201
14202     // private
14203     prepareEvent : function(e){
14204         var k = e.getKey();
14205         var h = this.keyToHandler[k];
14206         //if(h && this[h]){
14207         //    e.stopPropagation();
14208         //}
14209         if(Roo.isSafari && h && k >= 37 && k <= 40){
14210             e.stopEvent();
14211         }
14212     },
14213
14214     // private
14215     relay : function(e){
14216         var k = e.getKey();
14217         var h = this.keyToHandler[k];
14218         if(h && this[h]){
14219             if(this.doRelay(e, this[h], h) !== true){
14220                 e[this.defaultEventAction]();
14221             }
14222         }
14223     },
14224
14225     // private
14226     doRelay : function(e, h, hname){
14227         return h.call(this.scope || this, e);
14228     },
14229
14230     // possible handlers
14231     enter : false,
14232     left : false,
14233     right : false,
14234     up : false,
14235     down : false,
14236     tab : false,
14237     esc : false,
14238     pageUp : false,
14239     pageDown : false,
14240     del : false,
14241     home : false,
14242     end : false,
14243
14244     // quick lookup hash
14245     keyToHandler : {
14246         37 : "left",
14247         39 : "right",
14248         38 : "up",
14249         40 : "down",
14250         33 : "pageUp",
14251         34 : "pageDown",
14252         46 : "del",
14253         36 : "home",
14254         35 : "end",
14255         13 : "enter",
14256         27 : "esc",
14257         9  : "tab"
14258     },
14259
14260         /**
14261          * Enable this KeyNav
14262          */
14263         enable: function(){
14264                 if(this.disabled){
14265             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14266             // the EventObject will normalize Safari automatically
14267             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14268                 this.el.on("keydown", this.relay,  this);
14269             }else{
14270                 this.el.on("keydown", this.prepareEvent,  this);
14271                 this.el.on("keypress", this.relay,  this);
14272             }
14273                     this.disabled = false;
14274                 }
14275         },
14276
14277         /**
14278          * Disable this KeyNav
14279          */
14280         disable: function(){
14281                 if(!this.disabled){
14282                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14283                 this.el.un("keydown", this.relay);
14284             }else{
14285                 this.el.un("keydown", this.prepareEvent);
14286                 this.el.un("keypress", this.relay);
14287             }
14288                     this.disabled = true;
14289                 }
14290         }
14291 };/*
14292  * Based on:
14293  * Ext JS Library 1.1.1
14294  * Copyright(c) 2006-2007, Ext JS, LLC.
14295  *
14296  * Originally Released Under LGPL - original licence link has changed is not relivant.
14297  *
14298  * Fork - LGPL
14299  * <script type="text/javascript">
14300  */
14301
14302  
14303 /**
14304  * @class Roo.KeyMap
14305  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14306  * The constructor accepts the same config object as defined by {@link #addBinding}.
14307  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14308  * combination it will call the function with this signature (if the match is a multi-key
14309  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14310  * A KeyMap can also handle a string representation of keys.<br />
14311  * Usage:
14312  <pre><code>
14313 // map one key by key code
14314 var map = new Roo.KeyMap("my-element", {
14315     key: 13, // or Roo.EventObject.ENTER
14316     fn: myHandler,
14317     scope: myObject
14318 });
14319
14320 // map multiple keys to one action by string
14321 var map = new Roo.KeyMap("my-element", {
14322     key: "a\r\n\t",
14323     fn: myHandler,
14324     scope: myObject
14325 });
14326
14327 // map multiple keys to multiple actions by strings and array of codes
14328 var map = new Roo.KeyMap("my-element", [
14329     {
14330         key: [10,13],
14331         fn: function(){ alert("Return was pressed"); }
14332     }, {
14333         key: "abc",
14334         fn: function(){ alert('a, b or c was pressed'); }
14335     }, {
14336         key: "\t",
14337         ctrl:true,
14338         shift:true,
14339         fn: function(){ alert('Control + shift + tab was pressed.'); }
14340     }
14341 ]);
14342 </code></pre>
14343  * <b>Note: A KeyMap starts enabled</b>
14344  * @constructor
14345  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14346  * @param {Object} config The config (see {@link #addBinding})
14347  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14348  */
14349 Roo.KeyMap = function(el, config, eventName){
14350     this.el  = Roo.get(el);
14351     this.eventName = eventName || "keydown";
14352     this.bindings = [];
14353     if(config){
14354         this.addBinding(config);
14355     }
14356     this.enable();
14357 };
14358
14359 Roo.KeyMap.prototype = {
14360     /**
14361      * True to stop the event from bubbling and prevent the default browser action if the
14362      * key was handled by the KeyMap (defaults to false)
14363      * @type Boolean
14364      */
14365     stopEvent : false,
14366
14367     /**
14368      * Add a new binding to this KeyMap. The following config object properties are supported:
14369      * <pre>
14370 Property    Type             Description
14371 ----------  ---------------  ----------------------------------------------------------------------
14372 key         String/Array     A single keycode or an array of keycodes to handle
14373 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14374 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14375 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14376 fn          Function         The function to call when KeyMap finds the expected key combination
14377 scope       Object           The scope of the callback function
14378 </pre>
14379      *
14380      * Usage:
14381      * <pre><code>
14382 // Create a KeyMap
14383 var map = new Roo.KeyMap(document, {
14384     key: Roo.EventObject.ENTER,
14385     fn: handleKey,
14386     scope: this
14387 });
14388
14389 //Add a new binding to the existing KeyMap later
14390 map.addBinding({
14391     key: 'abc',
14392     shift: true,
14393     fn: handleKey,
14394     scope: this
14395 });
14396 </code></pre>
14397      * @param {Object/Array} config A single KeyMap config or an array of configs
14398      */
14399         addBinding : function(config){
14400         if(config instanceof Array){
14401             for(var i = 0, len = config.length; i < len; i++){
14402                 this.addBinding(config[i]);
14403             }
14404             return;
14405         }
14406         var keyCode = config.key,
14407             shift = config.shift, 
14408             ctrl = config.ctrl, 
14409             alt = config.alt,
14410             fn = config.fn,
14411             scope = config.scope;
14412         if(typeof keyCode == "string"){
14413             var ks = [];
14414             var keyString = keyCode.toUpperCase();
14415             for(var j = 0, len = keyString.length; j < len; j++){
14416                 ks.push(keyString.charCodeAt(j));
14417             }
14418             keyCode = ks;
14419         }
14420         var keyArray = keyCode instanceof Array;
14421         var handler = function(e){
14422             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14423                 var k = e.getKey();
14424                 if(keyArray){
14425                     for(var i = 0, len = keyCode.length; i < len; i++){
14426                         if(keyCode[i] == k){
14427                           if(this.stopEvent){
14428                               e.stopEvent();
14429                           }
14430                           fn.call(scope || window, k, e);
14431                           return;
14432                         }
14433                     }
14434                 }else{
14435                     if(k == keyCode){
14436                         if(this.stopEvent){
14437                            e.stopEvent();
14438                         }
14439                         fn.call(scope || window, k, e);
14440                     }
14441                 }
14442             }
14443         };
14444         this.bindings.push(handler);  
14445         },
14446
14447     /**
14448      * Shorthand for adding a single key listener
14449      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14450      * following options:
14451      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14452      * @param {Function} fn The function to call
14453      * @param {Object} scope (optional) The scope of the function
14454      */
14455     on : function(key, fn, scope){
14456         var keyCode, shift, ctrl, alt;
14457         if(typeof key == "object" && !(key instanceof Array)){
14458             keyCode = key.key;
14459             shift = key.shift;
14460             ctrl = key.ctrl;
14461             alt = key.alt;
14462         }else{
14463             keyCode = key;
14464         }
14465         this.addBinding({
14466             key: keyCode,
14467             shift: shift,
14468             ctrl: ctrl,
14469             alt: alt,
14470             fn: fn,
14471             scope: scope
14472         })
14473     },
14474
14475     // private
14476     handleKeyDown : function(e){
14477             if(this.enabled){ //just in case
14478             var b = this.bindings;
14479             for(var i = 0, len = b.length; i < len; i++){
14480                 b[i].call(this, e);
14481             }
14482             }
14483         },
14484         
14485         /**
14486          * Returns true if this KeyMap is enabled
14487          * @return {Boolean} 
14488          */
14489         isEnabled : function(){
14490             return this.enabled;  
14491         },
14492         
14493         /**
14494          * Enables this KeyMap
14495          */
14496         enable: function(){
14497                 if(!this.enabled){
14498                     this.el.on(this.eventName, this.handleKeyDown, this);
14499                     this.enabled = true;
14500                 }
14501         },
14502
14503         /**
14504          * Disable this KeyMap
14505          */
14506         disable: function(){
14507                 if(this.enabled){
14508                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14509                     this.enabled = false;
14510                 }
14511         }
14512 };/*
14513  * Based on:
14514  * Ext JS Library 1.1.1
14515  * Copyright(c) 2006-2007, Ext JS, LLC.
14516  *
14517  * Originally Released Under LGPL - original licence link has changed is not relivant.
14518  *
14519  * Fork - LGPL
14520  * <script type="text/javascript">
14521  */
14522
14523  
14524 /**
14525  * @class Roo.util.TextMetrics
14526  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14527  * wide, in pixels, a given block of text will be.
14528  * @singleton
14529  */
14530 Roo.util.TextMetrics = function(){
14531     var shared;
14532     return {
14533         /**
14534          * Measures the size of the specified text
14535          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14536          * that can affect the size of the rendered text
14537          * @param {String} text The text to measure
14538          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14539          * in order to accurately measure the text height
14540          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14541          */
14542         measure : function(el, text, fixedWidth){
14543             if(!shared){
14544                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14545             }
14546             shared.bind(el);
14547             shared.setFixedWidth(fixedWidth || 'auto');
14548             return shared.getSize(text);
14549         },
14550
14551         /**
14552          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14553          * the overhead of multiple calls to initialize the style properties on each measurement.
14554          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14555          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14556          * in order to accurately measure the text height
14557          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14558          */
14559         createInstance : function(el, fixedWidth){
14560             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14561         }
14562     };
14563 }();
14564
14565  
14566
14567 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14568     var ml = new Roo.Element(document.createElement('div'));
14569     document.body.appendChild(ml.dom);
14570     ml.position('absolute');
14571     ml.setLeftTop(-1000, -1000);
14572     ml.hide();
14573
14574     if(fixedWidth){
14575         ml.setWidth(fixedWidth);
14576     }
14577      
14578     var instance = {
14579         /**
14580          * Returns the size of the specified text based on the internal element's style and width properties
14581          * @memberOf Roo.util.TextMetrics.Instance#
14582          * @param {String} text The text to measure
14583          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14584          */
14585         getSize : function(text){
14586             ml.update(text);
14587             var s = ml.getSize();
14588             ml.update('');
14589             return s;
14590         },
14591
14592         /**
14593          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14594          * that can affect the size of the rendered text
14595          * @memberOf Roo.util.TextMetrics.Instance#
14596          * @param {String/HTMLElement} el The element, dom node or id
14597          */
14598         bind : function(el){
14599             ml.setStyle(
14600                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14601             );
14602         },
14603
14604         /**
14605          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14606          * to set a fixed width in order to accurately measure the text height.
14607          * @memberOf Roo.util.TextMetrics.Instance#
14608          * @param {Number} width The width to set on the element
14609          */
14610         setFixedWidth : function(width){
14611             ml.setWidth(width);
14612         },
14613
14614         /**
14615          * Returns the measured width of the specified text
14616          * @memberOf Roo.util.TextMetrics.Instance#
14617          * @param {String} text The text to measure
14618          * @return {Number} width The width in pixels
14619          */
14620         getWidth : function(text){
14621             ml.dom.style.width = 'auto';
14622             return this.getSize(text).width;
14623         },
14624
14625         /**
14626          * Returns the measured height of the specified text.  For multiline text, be sure to call
14627          * {@link #setFixedWidth} if necessary.
14628          * @memberOf Roo.util.TextMetrics.Instance#
14629          * @param {String} text The text to measure
14630          * @return {Number} height The height in pixels
14631          */
14632         getHeight : function(text){
14633             return this.getSize(text).height;
14634         }
14635     };
14636
14637     instance.bind(bindTo);
14638
14639     return instance;
14640 };
14641
14642 // backwards compat
14643 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14644  * Based on:
14645  * Ext JS Library 1.1.1
14646  * Copyright(c) 2006-2007, Ext JS, LLC.
14647  *
14648  * Originally Released Under LGPL - original licence link has changed is not relivant.
14649  *
14650  * Fork - LGPL
14651  * <script type="text/javascript">
14652  */
14653
14654 /**
14655  * @class Roo.state.Provider
14656  * Abstract base class for state provider implementations. This class provides methods
14657  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14658  * Provider interface.
14659  */
14660 Roo.state.Provider = function(){
14661     /**
14662      * @event statechange
14663      * Fires when a state change occurs.
14664      * @param {Provider} this This state provider
14665      * @param {String} key The state key which was changed
14666      * @param {String} value The encoded value for the state
14667      */
14668     this.addEvents({
14669         "statechange": true
14670     });
14671     this.state = {};
14672     Roo.state.Provider.superclass.constructor.call(this);
14673 };
14674 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14675     /**
14676      * Returns the current value for a key
14677      * @param {String} name The key name
14678      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14679      * @return {Mixed} The state data
14680      */
14681     get : function(name, defaultValue){
14682         return typeof this.state[name] == "undefined" ?
14683             defaultValue : this.state[name];
14684     },
14685     
14686     /**
14687      * Clears a value from the state
14688      * @param {String} name The key name
14689      */
14690     clear : function(name){
14691         delete this.state[name];
14692         this.fireEvent("statechange", this, name, null);
14693     },
14694     
14695     /**
14696      * Sets the value for a key
14697      * @param {String} name The key name
14698      * @param {Mixed} value The value to set
14699      */
14700     set : function(name, value){
14701         this.state[name] = value;
14702         this.fireEvent("statechange", this, name, value);
14703     },
14704     
14705     /**
14706      * Decodes a string previously encoded with {@link #encodeValue}.
14707      * @param {String} value The value to decode
14708      * @return {Mixed} The decoded value
14709      */
14710     decodeValue : function(cookie){
14711         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14712         var matches = re.exec(unescape(cookie));
14713         if(!matches || !matches[1]) return; // non state cookie
14714         var type = matches[1];
14715         var v = matches[2];
14716         switch(type){
14717             case "n":
14718                 return parseFloat(v);
14719             case "d":
14720                 return new Date(Date.parse(v));
14721             case "b":
14722                 return (v == "1");
14723             case "a":
14724                 var all = [];
14725                 var values = v.split("^");
14726                 for(var i = 0, len = values.length; i < len; i++){
14727                     all.push(this.decodeValue(values[i]));
14728                 }
14729                 return all;
14730            case "o":
14731                 var all = {};
14732                 var values = v.split("^");
14733                 for(var i = 0, len = values.length; i < len; i++){
14734                     var kv = values[i].split("=");
14735                     all[kv[0]] = this.decodeValue(kv[1]);
14736                 }
14737                 return all;
14738            default:
14739                 return v;
14740         }
14741     },
14742     
14743     /**
14744      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14745      * @param {Mixed} value The value to encode
14746      * @return {String} The encoded value
14747      */
14748     encodeValue : function(v){
14749         var enc;
14750         if(typeof v == "number"){
14751             enc = "n:" + v;
14752         }else if(typeof v == "boolean"){
14753             enc = "b:" + (v ? "1" : "0");
14754         }else if(v instanceof Date){
14755             enc = "d:" + v.toGMTString();
14756         }else if(v instanceof Array){
14757             var flat = "";
14758             for(var i = 0, len = v.length; i < len; i++){
14759                 flat += this.encodeValue(v[i]);
14760                 if(i != len-1) flat += "^";
14761             }
14762             enc = "a:" + flat;
14763         }else if(typeof v == "object"){
14764             var flat = "";
14765             for(var key in v){
14766                 if(typeof v[key] != "function"){
14767                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14768                 }
14769             }
14770             enc = "o:" + flat.substring(0, flat.length-1);
14771         }else{
14772             enc = "s:" + v;
14773         }
14774         return escape(enc);        
14775     }
14776 });
14777
14778 /*
14779  * Based on:
14780  * Ext JS Library 1.1.1
14781  * Copyright(c) 2006-2007, Ext JS, LLC.
14782  *
14783  * Originally Released Under LGPL - original licence link has changed is not relivant.
14784  *
14785  * Fork - LGPL
14786  * <script type="text/javascript">
14787  */
14788 /**
14789  * @class Roo.state.Manager
14790  * This is the global state manager. By default all components that are "state aware" check this class
14791  * for state information if you don't pass them a custom state provider. In order for this class
14792  * to be useful, it must be initialized with a provider when your application initializes.
14793  <pre><code>
14794 // in your initialization function
14795 init : function(){
14796    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14797    ...
14798    // supposed you have a {@link Roo.BorderLayout}
14799    var layout = new Roo.BorderLayout(...);
14800    layout.restoreState();
14801    // or a {Roo.BasicDialog}
14802    var dialog = new Roo.BasicDialog(...);
14803    dialog.restoreState();
14804  </code></pre>
14805  * @singleton
14806  */
14807 Roo.state.Manager = function(){
14808     var provider = new Roo.state.Provider();
14809     
14810     return {
14811         /**
14812          * Configures the default state provider for your application
14813          * @param {Provider} stateProvider The state provider to set
14814          */
14815         setProvider : function(stateProvider){
14816             provider = stateProvider;
14817         },
14818         
14819         /**
14820          * Returns the current value for a key
14821          * @param {String} name The key name
14822          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14823          * @return {Mixed} The state data
14824          */
14825         get : function(key, defaultValue){
14826             return provider.get(key, defaultValue);
14827         },
14828         
14829         /**
14830          * Sets the value for a key
14831          * @param {String} name The key name
14832          * @param {Mixed} value The state data
14833          */
14834          set : function(key, value){
14835             provider.set(key, value);
14836         },
14837         
14838         /**
14839          * Clears a value from the state
14840          * @param {String} name The key name
14841          */
14842         clear : function(key){
14843             provider.clear(key);
14844         },
14845         
14846         /**
14847          * Gets the currently configured state provider
14848          * @return {Provider} The state provider
14849          */
14850         getProvider : function(){
14851             return provider;
14852         }
14853     };
14854 }();
14855 /*
14856  * Based on:
14857  * Ext JS Library 1.1.1
14858  * Copyright(c) 2006-2007, Ext JS, LLC.
14859  *
14860  * Originally Released Under LGPL - original licence link has changed is not relivant.
14861  *
14862  * Fork - LGPL
14863  * <script type="text/javascript">
14864  */
14865 /**
14866  * @class Roo.state.CookieProvider
14867  * @extends Roo.state.Provider
14868  * The default Provider implementation which saves state via cookies.
14869  * <br />Usage:
14870  <pre><code>
14871    var cp = new Roo.state.CookieProvider({
14872        path: "/cgi-bin/",
14873        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14874        domain: "roojs.com"
14875    })
14876    Roo.state.Manager.setProvider(cp);
14877  </code></pre>
14878  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14879  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14880  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14881  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14882  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14883  * domain the page is running on including the 'www' like 'www.roojs.com')
14884  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14885  * @constructor
14886  * Create a new CookieProvider
14887  * @param {Object} config The configuration object
14888  */
14889 Roo.state.CookieProvider = function(config){
14890     Roo.state.CookieProvider.superclass.constructor.call(this);
14891     this.path = "/";
14892     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14893     this.domain = null;
14894     this.secure = false;
14895     Roo.apply(this, config);
14896     this.state = this.readCookies();
14897 };
14898
14899 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14900     // private
14901     set : function(name, value){
14902         if(typeof value == "undefined" || value === null){
14903             this.clear(name);
14904             return;
14905         }
14906         this.setCookie(name, value);
14907         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14908     },
14909
14910     // private
14911     clear : function(name){
14912         this.clearCookie(name);
14913         Roo.state.CookieProvider.superclass.clear.call(this, name);
14914     },
14915
14916     // private
14917     readCookies : function(){
14918         var cookies = {};
14919         var c = document.cookie + ";";
14920         var re = /\s?(.*?)=(.*?);/g;
14921         var matches;
14922         while((matches = re.exec(c)) != null){
14923             var name = matches[1];
14924             var value = matches[2];
14925             if(name && name.substring(0,3) == "ys-"){
14926                 cookies[name.substr(3)] = this.decodeValue(value);
14927             }
14928         }
14929         return cookies;
14930     },
14931
14932     // private
14933     setCookie : function(name, value){
14934         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14935            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14936            ((this.path == null) ? "" : ("; path=" + this.path)) +
14937            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14938            ((this.secure == true) ? "; secure" : "");
14939     },
14940
14941     // private
14942     clearCookie : function(name){
14943         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14944            ((this.path == null) ? "" : ("; path=" + this.path)) +
14945            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14946            ((this.secure == true) ? "; secure" : "");
14947     }
14948 });