Roo/dd/DDProxy.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         isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
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         /** @type Boolean */
619         isTouch : isTouch,
620
621         /**
622          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623          * you may want to set this to true.
624          * @type Boolean
625          */
626         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
627         
628         
629                 
630         /**
631          * Selects a single element as a Roo Element
632          * This is about as close as you can get to jQuery's $('do crazy stuff')
633          * @param {String} selector The selector/xpath query
634          * @param {Node} root (optional) The start of the query (defaults to document).
635          * @return {Roo.Element}
636          */
637         selectNode : function(selector, root) 
638         {
639             var node = Roo.DomQuery.selectNode(selector,root);
640             return node ? Roo.get(node) : new Roo.Element(false);
641         }
642         
643     });
644
645
646 })();
647
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 /*
651  * Based on:
652  * Ext JS Library 1.1.1
653  * Copyright(c) 2006-2007, Ext JS, LLC.
654  *
655  * Originally Released Under LGPL - original licence link has changed is not relivant.
656  *
657  * Fork - LGPL
658  * <script type="text/javascript">
659  */
660
661 (function() {    
662     // wrappedn so fnCleanup is not in global scope...
663     if(Roo.isIE) {
664         function fnCleanUp() {
665             var p = Function.prototype;
666             delete p.createSequence;
667             delete p.defer;
668             delete p.createDelegate;
669             delete p.createCallback;
670             delete p.createInterceptor;
671
672             window.detachEvent("onunload", fnCleanUp);
673         }
674         window.attachEvent("onunload", fnCleanUp);
675     }
676 })();
677
678
679 /**
680  * @class Function
681  * These functions are available on every Function object (any JavaScript function).
682  */
683 Roo.apply(Function.prototype, {
684      /**
685      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687      * Will create a function that is bound to those 2 args.
688      * @return {Function} The new function
689     */
690     createCallback : function(/*args...*/){
691         // make args available, in function below
692         var args = arguments;
693         var method = this;
694         return function() {
695             return method.apply(window, args);
696         };
697     },
698
699     /**
700      * Creates a delegate (callback) that sets the scope to obj.
701      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702      * Will create a function that is automatically scoped to this.
703      * @param {Object} obj (optional) The object for which the scope is set
704      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706      *                                             if a number the args are inserted at the specified position
707      * @return {Function} The new function
708      */
709     createDelegate : function(obj, args, appendArgs){
710         var method = this;
711         return function() {
712             var callArgs = args || arguments;
713             if(appendArgs === true){
714                 callArgs = Array.prototype.slice.call(arguments, 0);
715                 callArgs = callArgs.concat(args);
716             }else if(typeof appendArgs == "number"){
717                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
720             }
721             return method.apply(obj || window, callArgs);
722         };
723     },
724
725     /**
726      * Calls this function after the number of millseconds specified.
727      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728      * @param {Object} obj (optional) The object for which the scope is set
729      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731      *                                             if a number the args are inserted at the specified position
732      * @return {Number} The timeout id that can be used with clearTimeout
733      */
734     defer : function(millis, obj, args, appendArgs){
735         var fn = this.createDelegate(obj, args, appendArgs);
736         if(millis){
737             return setTimeout(fn, millis);
738         }
739         fn();
740         return 0;
741     },
742     /**
743      * Create a combined function call sequence of the original function + the passed function.
744      * The resulting function returns the results of the original function.
745      * The passed fcn is called with the parameters of the original function
746      * @param {Function} fcn The function to sequence
747      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748      * @return {Function} The new function
749      */
750     createSequence : function(fcn, scope){
751         if(typeof fcn != "function"){
752             return this;
753         }
754         var method = this;
755         return function() {
756             var retval = method.apply(this || window, arguments);
757             fcn.apply(scope || this || window, arguments);
758             return retval;
759         };
760     },
761
762     /**
763      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function.
766      * @addon
767      * @param {Function} fcn The function to call before the original
768      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769      * @return {Function} The new function
770      */
771     createInterceptor : function(fcn, scope){
772         if(typeof fcn != "function"){
773             return this;
774         }
775         var method = this;
776         return function() {
777             fcn.target = this;
778             fcn.method = method;
779             if(fcn.apply(scope || this || window, arguments) === false){
780                 return;
781             }
782             return method.apply(this || window, arguments);
783         };
784     }
785 });
786 /*
787  * Based on:
788  * Ext JS Library 1.1.1
789  * Copyright(c) 2006-2007, Ext JS, LLC.
790  *
791  * Originally Released Under LGPL - original licence link has changed is not relivant.
792  *
793  * Fork - LGPL
794  * <script type="text/javascript">
795  */
796
797 Roo.applyIf(String, {
798     
799     /** @scope String */
800     
801     /**
802      * Escapes the passed string for ' and \
803      * @param {String} string The string to escape
804      * @return {String} The escaped string
805      * @static
806      */
807     escape : function(string) {
808         return string.replace(/('|\\)/g, "\\$1");
809     },
810
811     /**
812      * Pads the left side of a string with a specified character.  This is especially useful
813      * for normalizing number and date strings.  Example usage:
814      * <pre><code>
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
817 </code></pre>
818      * @param {String} string The original string
819      * @param {Number} size The total length of the output string
820      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821      * @return {String} The padded string
822      * @static
823      */
824     leftPad : function (val, size, ch) {
825         var result = new String(val);
826         if(ch === null || ch === undefined || ch === '') {
827             ch = " ";
828         }
829         while (result.length < size) {
830             result = ch + result;
831         }
832         return result;
833     },
834
835     /**
836      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
837      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
838      * <pre><code>
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
842 </code></pre>
843      * @param {String} string The tokenized string to be formatted
844      * @param {String} value1 The value to replace token {0}
845      * @param {String} value2 Etc...
846      * @return {String} The formatted string
847      * @static
848      */
849     format : function(format){
850         var args = Array.prototype.slice.call(arguments, 1);
851         return format.replace(/\{(\d+)\}/g, function(m, i){
852             return Roo.util.Format.htmlEncode(args[i]);
853         });
854     }
855 });
856
857 /**
858  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
859  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
860  * they are already different, the first value passed in is returned.  Note that this method returns the new value
861  * but does not change the current string.
862  * <pre><code>
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
865
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
868 </code></pre>
869  * @param {String} value The value to compare to the current string
870  * @param {String} other The new value to use if the string already equals the first value passed in
871  * @return {String} The new value
872  */
873  
874 String.prototype.toggle = function(value, other){
875     return this == value ? other : value;
876 };/*
877  * Based on:
878  * Ext JS Library 1.1.1
879  * Copyright(c) 2006-2007, Ext JS, LLC.
880  *
881  * Originally Released Under LGPL - original licence link has changed is not relivant.
882  *
883  * Fork - LGPL
884  * <script type="text/javascript">
885  */
886
887  /**
888  * @class Number
889  */
890 Roo.applyIf(Number.prototype, {
891     /**
892      * Checks whether or not the current number is within a desired range.  If the number is already within the
893      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894      * exceeded.  Note that this method returns the constrained value but does not change the current number.
895      * @param {Number} min The minimum number in the range
896      * @param {Number} max The maximum number in the range
897      * @return {Number} The constrained value if outside the range, otherwise the current value
898      */
899     constrain : function(min, max){
900         return Math.min(Math.max(this, min), max);
901     }
902 });/*
903  * Based on:
904  * Ext JS Library 1.1.1
905  * Copyright(c) 2006-2007, Ext JS, LLC.
906  *
907  * Originally Released Under LGPL - original licence link has changed is not relivant.
908  *
909  * Fork - LGPL
910  * <script type="text/javascript">
911  */
912  /**
913  * @class Array
914  */
915 Roo.applyIf(Array.prototype, {
916     /**
917      * Checks whether or not the specified object exists in the array.
918      * @param {Object} o The object to check for
919      * @return {Number} The index of o in the array (or -1 if it is not found)
920      */
921     indexOf : function(o){
922        for (var i = 0, len = this.length; i < len; i++){
923               if(this[i] == o) return i;
924        }
925            return -1;
926     },
927
928     /**
929      * Removes the specified object from the array.  If the object is not found nothing happens.
930      * @param {Object} o The object to remove
931      */
932     remove : function(o){
933        var index = this.indexOf(o);
934        if(index != -1){
935            this.splice(index, 1);
936        }
937     },
938     /**
939      * Map (JS 1.6 compatibility)
940      * @param {Function} function  to call
941      */
942     map : function(fun )
943     {
944         var len = this.length >>> 0;
945         if (typeof fun != "function")
946             throw new TypeError();
947
948         var res = new Array(len);
949         var thisp = arguments[1];
950         for (var i = 0; i < len; i++)
951         {
952             if (i in this)
953                 res[i] = fun.call(thisp, this[i], i, this);
954         }
955
956         return res;
957     }
958     
959 });
960
961
962  /*
963  * Based on:
964  * Ext JS Library 1.1.1
965  * Copyright(c) 2006-2007, Ext JS, LLC.
966  *
967  * Originally Released Under LGPL - original licence link has changed is not relivant.
968  *
969  * Fork - LGPL
970  * <script type="text/javascript">
971  */
972
973 /**
974  * @class Date
975  *
976  * The date parsing and format syntax is a subset of
977  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978  * supported will provide results equivalent to their PHP versions.
979  *
980  * Following is the list of all currently supported formats:
981  *<pre>
982 Sample date:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
984
985 Format  Output      Description
986 ------  ----------  --------------------------------------------------------------
987   d      10         Day of the month, 2 digits with leading zeros
988   D      Wed        A textual representation of a day, three letters
989   j      10         Day of the month without leading zeros
990   l      Wednesday  A full textual representation of the day of the week
991   S      th         English ordinal day of month suffix, 2 chars (use with j)
992   w      3          Numeric representation of the day of the week
993   z      9          The julian date, or day of the year (0-365)
994   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995   F      January    A full textual representation of the month
996   m      01         Numeric representation of a month, with leading zeros
997   M      Jan        Month name abbreviation, three letters
998   n      1          Numeric representation of a month, without leading zeros
999   t      31         Number of days in the given month
1000   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1001   Y      2007       A full numeric representation of a year, 4 digits
1002   y      07         A two digit representation of a year
1003   a      pm         Lowercase Ante meridiem and Post meridiem
1004   A      PM         Uppercase Ante meridiem and Post meridiem
1005   g      3          12-hour format of an hour without leading zeros
1006   G      15         24-hour format of an hour without leading zeros
1007   h      03         12-hour format of an hour with leading zeros
1008   H      15         24-hour format of an hour with leading zeros
1009   i      05         Minutes with leading zeros
1010   s      01         Seconds, with leading zeros
1011   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1013   T      CST        Timezone setting of the machine running the code
1014   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1015 </pre>
1016  *
1017  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1018  * <pre><code>
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d'));                         //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1022 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
1023  </code></pre>
1024  *
1025  * Here are some standard date/time patterns that you might find helpful.  They
1026  * are not part of the source of Date.js, but to use them you can simply copy this
1027  * block of code into any script that is included after Date.js and they will also become
1028  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1029  * <pre><code>
1030 Date.patterns = {
1031     ISO8601Long:"Y-m-d H:i:s",
1032     ISO8601Short:"Y-m-d",
1033     ShortDate: "n/j/Y",
1034     LongDate: "l, F d, Y",
1035     FullDateTime: "l, F d, Y g:i:s A",
1036     MonthDay: "F d",
1037     ShortTime: "g:i A",
1038     LongTime: "g:i:s A",
1039     SortableDateTime: "Y-m-d\\TH:i:s",
1040     UniversalSortableDateTime: "Y-m-d H:i:sO",
1041     YearMonth: "F, Y"
1042 };
1043 </code></pre>
1044  *
1045  * Example usage:
1046  * <pre><code>
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1049  </code></pre>
1050  */
1051
1052 /*
1053  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054  * They generate precompiled functions from date formats instead of parsing and
1055  * processing the pattern every time you format a date.  These functions are available
1056  * on every Date object (any javascript function).
1057  *
1058  * The original article and download are here:
1059  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1060  *
1061  */
1062  
1063  
1064  // was in core
1065 /**
1066  Returns the number of milliseconds between this date and date
1067  @param {Date} date (optional) Defaults to now
1068  @return {Number} The diff in milliseconds
1069  @member Date getElapsed
1070  */
1071 Date.prototype.getElapsed = function(date) {
1072         return Math.abs((date || new Date()).getTime()-this.getTime());
1073 };
1074 // was in date file..
1075
1076
1077 // private
1078 Date.parseFunctions = {count:0};
1079 // private
1080 Date.parseRegexes = [];
1081 // private
1082 Date.formatFunctions = {count:0};
1083
1084 // private
1085 Date.prototype.dateFormat = function(format) {
1086     if (Date.formatFunctions[format] == null) {
1087         Date.createNewFormat(format);
1088     }
1089     var func = Date.formatFunctions[format];
1090     return this[func]();
1091 };
1092
1093
1094 /**
1095  * Formats a date given the supplied format string
1096  * @param {String} format The format string
1097  * @return {String} The formatted date
1098  * @method
1099  */
1100 Date.prototype.format = Date.prototype.dateFormat;
1101
1102 // private
1103 Date.createNewFormat = function(format) {
1104     var funcName = "format" + Date.formatFunctions.count++;
1105     Date.formatFunctions[format] = funcName;
1106     var code = "Date.prototype." + funcName + " = function(){return ";
1107     var special = false;
1108     var ch = '';
1109     for (var i = 0; i < format.length; ++i) {
1110         ch = format.charAt(i);
1111         if (!special && ch == "\\") {
1112             special = true;
1113         }
1114         else if (special) {
1115             special = false;
1116             code += "'" + String.escape(ch) + "' + ";
1117         }
1118         else {
1119             code += Date.getFormatCode(ch);
1120         }
1121     }
1122     /** eval:var:zzzzzzzzzzzzz */
1123     eval(code.substring(0, code.length - 3) + ";}");
1124 };
1125
1126 // private
1127 Date.getFormatCode = function(character) {
1128     switch (character) {
1129     case "d":
1130         return "String.leftPad(this.getDate(), 2, '0') + ";
1131     case "D":
1132         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1133     case "j":
1134         return "this.getDate() + ";
1135     case "l":
1136         return "Date.dayNames[this.getDay()] + ";
1137     case "S":
1138         return "this.getSuffix() + ";
1139     case "w":
1140         return "this.getDay() + ";
1141     case "z":
1142         return "this.getDayOfYear() + ";
1143     case "W":
1144         return "this.getWeekOfYear() + ";
1145     case "F":
1146         return "Date.monthNames[this.getMonth()] + ";
1147     case "m":
1148         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1149     case "M":
1150         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1151     case "n":
1152         return "(this.getMonth() + 1) + ";
1153     case "t":
1154         return "this.getDaysInMonth() + ";
1155     case "L":
1156         return "(this.isLeapYear() ? 1 : 0) + ";
1157     case "Y":
1158         return "this.getFullYear() + ";
1159     case "y":
1160         return "('' + this.getFullYear()).substring(2, 4) + ";
1161     case "a":
1162         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1163     case "A":
1164         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1165     case "g":
1166         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1167     case "G":
1168         return "this.getHours() + ";
1169     case "h":
1170         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1171     case "H":
1172         return "String.leftPad(this.getHours(), 2, '0') + ";
1173     case "i":
1174         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1175     case "s":
1176         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1177     case "O":
1178         return "this.getGMTOffset() + ";
1179     case "P":
1180         return "this.getGMTColonOffset() + ";
1181     case "T":
1182         return "this.getTimezone() + ";
1183     case "Z":
1184         return "(this.getTimezoneOffset() * -60) + ";
1185     default:
1186         return "'" + String.escape(character) + "' + ";
1187     }
1188 };
1189
1190 /**
1191  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1193  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1194  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1195  * string or the parse operation will fail.
1196  * Example Usage:
1197 <pre><code>
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1200
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1203
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1206
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1209 </code></pre>
1210  * @param {String} input The unparsed date as a string
1211  * @param {String} format The format the date is in
1212  * @return {Date} The parsed date
1213  * @static
1214  */
1215 Date.parseDate = function(input, format) {
1216     if (Date.parseFunctions[format] == null) {
1217         Date.createParser(format);
1218     }
1219     var func = Date.parseFunctions[format];
1220     return Date[func](input);
1221 };
1222 /**
1223  * @private
1224  */
1225 Date.createParser = function(format) {
1226     var funcName = "parse" + Date.parseFunctions.count++;
1227     var regexNum = Date.parseRegexes.length;
1228     var currentGroup = 1;
1229     Date.parseFunctions[format] = funcName;
1230
1231     var code = "Date." + funcName + " = function(input){\n"
1232         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233         + "var d = new Date();\n"
1234         + "y = d.getFullYear();\n"
1235         + "m = d.getMonth();\n"
1236         + "d = d.getDate();\n"
1237         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238         + "if (results && results.length > 0) {";
1239     var regex = "";
1240
1241     var special = false;
1242     var ch = '';
1243     for (var i = 0; i < format.length; ++i) {
1244         ch = format.charAt(i);
1245         if (!special && ch == "\\") {
1246             special = true;
1247         }
1248         else if (special) {
1249             special = false;
1250             regex += String.escape(ch);
1251         }
1252         else {
1253             var obj = Date.formatCodeToRegex(ch, currentGroup);
1254             currentGroup += obj.g;
1255             regex += obj.s;
1256             if (obj.g && obj.c) {
1257                 code += obj.c;
1258             }
1259         }
1260     }
1261
1262     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i, s);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265         + "{v = new Date(y, m, d, h, i);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267         + "{v = new Date(y, m, d, h);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269         + "{v = new Date(y, m, d);}\n"
1270         + "else if (y >= 0 && m >= 0)\n"
1271         + "{v = new Date(y, m);}\n"
1272         + "else if (y >= 0)\n"
1273         + "{v = new Date(y);}\n"
1274         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277         + ";}";
1278
1279     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280     /** eval:var:zzzzzzzzzzzzz */
1281     eval(code);
1282 };
1283
1284 // private
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286     switch (character) {
1287     case "D":
1288         return {g:0,
1289         c:null,
1290         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291     case "j":
1292         return {g:1,
1293             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294             s:"(\\d{1,2})"}; // day of month without leading zeroes
1295     case "d":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{2})"}; // day of month with leading zeroes
1299     case "l":
1300         return {g:0,
1301             c:null,
1302             s:"(?:" + Date.dayNames.join("|") + ")"};
1303     case "S":
1304         return {g:0,
1305             c:null,
1306             s:"(?:st|nd|rd|th)"};
1307     case "w":
1308         return {g:0,
1309             c:null,
1310             s:"\\d"};
1311     case "z":
1312         return {g:0,
1313             c:null,
1314             s:"(?:\\d{1,3})"};
1315     case "W":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{2})"};
1319     case "F":
1320         return {g:1,
1321             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322             s:"(" + Date.monthNames.join("|") + ")"};
1323     case "M":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327     case "n":
1328         return {g:1,
1329             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331     case "m":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1335     case "t":
1336         return {g:0,
1337             c:null,
1338             s:"\\d{1,2}"};
1339     case "L":
1340         return {g:0,
1341             c:null,
1342             s:"(?:1|0)"};
1343     case "Y":
1344         return {g:1,
1345             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1346             s:"(\\d{4})"};
1347     case "y":
1348         return {g:1,
1349             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1351             s:"(\\d{1,2})"};
1352     case "a":
1353         return {g:1,
1354             c:"if (results[" + currentGroup + "] == 'am') {\n"
1355                 + "if (h == 12) { h = 0; }\n"
1356                 + "} else { if (h < 12) { h += 12; }}",
1357             s:"(am|pm)"};
1358     case "A":
1359         return {g:1,
1360             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361                 + "if (h == 12) { h = 0; }\n"
1362                 + "} else { if (h < 12) { h += 12; }}",
1363             s:"(AM|PM)"};
1364     case "g":
1365     case "G":
1366         return {g:1,
1367             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1369     case "h":
1370     case "H":
1371         return {g:1,
1372             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1374     case "i":
1375         return {g:1,
1376             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"};
1378     case "s":
1379         return {g:1,
1380             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "O":
1383         return {g:1,
1384             c:[
1385                 "o = results[", currentGroup, "];\n",
1386                 "var sn = o.substring(0,1);\n", // get + / - sign
1387                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391             ].join(""),
1392             s:"([+\-]\\d{2,4})"};
1393     
1394     
1395     case "P":
1396         return {g:1,
1397                 c:[
1398                    "o = results[", currentGroup, "];\n",
1399                    "var sn = o.substring(0,1);\n",
1400                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401                    "var mn = o.substring(4,6) % 60;\n",
1402                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1404             ].join(""),
1405             s:"([+\-]\\d{4})"};
1406     case "T":
1407         return {g:0,
1408             c:null,
1409             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410     case "Z":
1411         return {g:1,
1412             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1415     default:
1416         return {g:0,
1417             c:null,
1418             s:String.escape(character)};
1419     }
1420 };
1421
1422 /**
1423  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424  * @return {String} The abbreviated timezone name (e.g. 'CST')
1425  */
1426 Date.prototype.getTimezone = function() {
1427     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1428 };
1429
1430 /**
1431  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1433  */
1434 Date.prototype.getGMTOffset = function() {
1435     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1438 };
1439
1440 /**
1441  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442  * @return {String} 2-characters representing hours and 2-characters representing minutes
1443  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1444  */
1445 Date.prototype.getGMTColonOffset = function() {
1446         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1448                 + ":"
1449                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1450 }
1451
1452 /**
1453  * Get the numeric day number of the year, adjusted for leap year.
1454  * @return {Number} 0 through 364 (365 in leap years)
1455  */
1456 Date.prototype.getDayOfYear = function() {
1457     var num = 0;
1458     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459     for (var i = 0; i < this.getMonth(); ++i) {
1460         num += Date.daysInMonth[i];
1461     }
1462     return num + this.getDate() - 1;
1463 };
1464
1465 /**
1466  * Get the string representation of the numeric week number of the year
1467  * (equivalent to the format specifier 'W').
1468  * @return {String} '00' through '52'
1469  */
1470 Date.prototype.getWeekOfYear = function() {
1471     // Skip to Thursday of this week
1472     var now = this.getDayOfYear() + (4 - this.getDay());
1473     // Find the first Thursday of the year
1474     var jan1 = new Date(this.getFullYear(), 0, 1);
1475     var then = (7 - jan1.getDay() + 4);
1476     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1477 };
1478
1479 /**
1480  * Whether or not the current date is in a leap year.
1481  * @return {Boolean} True if the current date is in a leap year, else false
1482  */
1483 Date.prototype.isLeapYear = function() {
1484     var year = this.getFullYear();
1485     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1486 };
1487
1488 /**
1489  * Get the first day of the current month, adjusted for leap year.  The returned value
1490  * is the numeric day index within the week (0-6) which can be used in conjunction with
1491  * the {@link #monthNames} array to retrieve the textual day name.
1492  * Example:
1493  *<pre><code>
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1496 </code></pre>
1497  * @return {Number} The day number (0-6)
1498  */
1499 Date.prototype.getFirstDayOfMonth = function() {
1500     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501     return (day < 0) ? (day + 7) : day;
1502 };
1503
1504 /**
1505  * Get the last day of the current month, adjusted for leap year.  The returned value
1506  * is the numeric day index within the week (0-6) which can be used in conjunction with
1507  * the {@link #monthNames} array to retrieve the textual day name.
1508  * Example:
1509  *<pre><code>
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1512 </code></pre>
1513  * @return {Number} The day number (0-6)
1514  */
1515 Date.prototype.getLastDayOfMonth = function() {
1516     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517     return (day < 0) ? (day + 7) : day;
1518 };
1519
1520
1521 /**
1522  * Get the first date of this date's month
1523  * @return {Date}
1524  */
1525 Date.prototype.getFirstDateOfMonth = function() {
1526     return new Date(this.getFullYear(), this.getMonth(), 1);
1527 };
1528
1529 /**
1530  * Get the last date of this date's month
1531  * @return {Date}
1532  */
1533 Date.prototype.getLastDateOfMonth = function() {
1534     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 };
1536 /**
1537  * Get the number of days in the current month, adjusted for leap year.
1538  * @return {Number} The number of days in the month
1539  */
1540 Date.prototype.getDaysInMonth = function() {
1541     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542     return Date.daysInMonth[this.getMonth()];
1543 };
1544
1545 /**
1546  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547  * @return {String} 'st, 'nd', 'rd' or 'th'
1548  */
1549 Date.prototype.getSuffix = function() {
1550     switch (this.getDate()) {
1551         case 1:
1552         case 21:
1553         case 31:
1554             return "st";
1555         case 2:
1556         case 22:
1557             return "nd";
1558         case 3:
1559         case 23:
1560             return "rd";
1561         default:
1562             return "th";
1563     }
1564 };
1565
1566 // private
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568
1569 /**
1570  * An array of textual month names.
1571  * Override these values for international dates, for example...
1572  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1573  * @type Array
1574  * @static
1575  */
1576 Date.monthNames =
1577    ["January",
1578     "February",
1579     "March",
1580     "April",
1581     "May",
1582     "June",
1583     "July",
1584     "August",
1585     "September",
1586     "October",
1587     "November",
1588     "December"];
1589
1590 /**
1591  * An array of textual day names.
1592  * Override these values for international dates, for example...
1593  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1594  * @type Array
1595  * @static
1596  */
1597 Date.dayNames =
1598    ["Sunday",
1599     "Monday",
1600     "Tuesday",
1601     "Wednesday",
1602     "Thursday",
1603     "Friday",
1604     "Saturday"];
1605
1606 // private
1607 Date.y2kYear = 50;
1608 // private
1609 Date.monthNumbers = {
1610     Jan:0,
1611     Feb:1,
1612     Mar:2,
1613     Apr:3,
1614     May:4,
1615     Jun:5,
1616     Jul:6,
1617     Aug:7,
1618     Sep:8,
1619     Oct:9,
1620     Nov:10,
1621     Dec:11};
1622
1623 /**
1624  * Creates and returns a new Date instance with the exact same date value as the called instance.
1625  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626  * variable will also be changed.  When the intention is to create a new variable that will not
1627  * modify the original instance, you should create a clone.
1628  *
1629  * Example of correctly cloning a date:
1630  * <pre><code>
1631 //wrong way:
1632 var orig = new Date('10/1/2006');
1633 var copy = orig;
1634 copy.setDate(5);
1635 document.write(orig);  //returns 'Thu Oct 05 2006'!
1636
1637 //correct way:
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1640 copy.setDate(5);
1641 document.write(orig);  //returns 'Thu Oct 01 2006'
1642 </code></pre>
1643  * @return {Date} The new Date instance
1644  */
1645 Date.prototype.clone = function() {
1646         return new Date(this.getTime());
1647 };
1648
1649 /**
1650  * Clears any time information from this date
1651  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652  @return {Date} this or the clone
1653  */
1654 Date.prototype.clearTime = function(clone){
1655     if(clone){
1656         return this.clone().clearTime();
1657     }
1658     this.setHours(0);
1659     this.setMinutes(0);
1660     this.setSeconds(0);
1661     this.setMilliseconds(0);
1662     return this;
1663 };
1664
1665 // private
1666 // safari setMonth is broken
1667 if(Roo.isSafari){
1668     Date.brokenSetMonth = Date.prototype.setMonth;
1669         Date.prototype.setMonth = function(num){
1670                 if(num <= -1){
1671                         var n = Math.ceil(-num);
1672                         var back_year = Math.ceil(n/12);
1673                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1674                         this.setFullYear(this.getFullYear() - back_year);
1675                         return Date.brokenSetMonth.call(this, month);
1676                 } else {
1677                         return Date.brokenSetMonth.apply(this, arguments);
1678                 }
1679         };
1680 }
1681
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.MILLI = "ms";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.SECOND = "s";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.MINUTE = "mi";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.HOUR = "h";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.DAY = "d";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MONTH = "mo";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.YEAR = "y";
1710
1711 /**
1712  * Provides a convenient method of performing basic date arithmetic.  This method
1713  * does not modify the Date instance being called - it creates and returns
1714  * a new Date instance containing the resulting date value.
1715  *
1716  * Examples:
1717  * <pre><code>
1718 //Basic usage:
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1721
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1725
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729  </code></pre>
1730  *
1731  * @param {String} interval   A valid date interval enum value
1732  * @param {Number} value      The amount to add to the current date
1733  * @return {Date} The new Date instance
1734  */
1735 Date.prototype.add = function(interval, value){
1736   var d = this.clone();
1737   if (!interval || value === 0) return d;
1738   switch(interval.toLowerCase()){
1739     case Date.MILLI:
1740       d.setMilliseconds(this.getMilliseconds() + value);
1741       break;
1742     case Date.SECOND:
1743       d.setSeconds(this.getSeconds() + value);
1744       break;
1745     case Date.MINUTE:
1746       d.setMinutes(this.getMinutes() + value);
1747       break;
1748     case Date.HOUR:
1749       d.setHours(this.getHours() + value);
1750       break;
1751     case Date.DAY:
1752       d.setDate(this.getDate() + value);
1753       break;
1754     case Date.MONTH:
1755       var day = this.getDate();
1756       if(day > 28){
1757           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758       }
1759       d.setDate(day);
1760       d.setMonth(this.getMonth() + value);
1761       break;
1762     case Date.YEAR:
1763       d.setFullYear(this.getFullYear() + value);
1764       break;
1765   }
1766   return d;
1767 };
1768 /*
1769  * Based on:
1770  * Ext JS Library 1.1.1
1771  * Copyright(c) 2006-2007, Ext JS, LLC.
1772  *
1773  * Originally Released Under LGPL - original licence link has changed is not relivant.
1774  *
1775  * Fork - LGPL
1776  * <script type="text/javascript">
1777  */
1778
1779 /**
1780  * @class Roo.lib.Dom
1781  * @static
1782  * 
1783  * Dom utils (from YIU afaik)
1784  * 
1785  **/
1786 Roo.lib.Dom = {
1787     /**
1788      * Get the view width
1789      * @param {Boolean} full True will get the full document, otherwise it's the view width
1790      * @return {Number} The width
1791      */
1792      
1793     getViewWidth : function(full) {
1794         return full ? this.getDocumentWidth() : this.getViewportWidth();
1795     },
1796     /**
1797      * Get the view height
1798      * @param {Boolean} full True will get the full document, otherwise it's the view height
1799      * @return {Number} The height
1800      */
1801     getViewHeight : function(full) {
1802         return full ? this.getDocumentHeight() : this.getViewportHeight();
1803     },
1804
1805     getDocumentHeight: function() {
1806         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807         return Math.max(scrollHeight, this.getViewportHeight());
1808     },
1809
1810     getDocumentWidth: function() {
1811         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812         return Math.max(scrollWidth, this.getViewportWidth());
1813     },
1814
1815     getViewportHeight: function() {
1816         var height = self.innerHeight;
1817         var mode = document.compatMode;
1818
1819         if ((mode || Roo.isIE) && !Roo.isOpera) {
1820             height = (mode == "CSS1Compat") ?
1821                      document.documentElement.clientHeight :
1822                      document.body.clientHeight;
1823         }
1824
1825         return height;
1826     },
1827
1828     getViewportWidth: function() {
1829         var width = self.innerWidth;
1830         var mode = document.compatMode;
1831
1832         if (mode || Roo.isIE) {
1833             width = (mode == "CSS1Compat") ?
1834                     document.documentElement.clientWidth :
1835                     document.body.clientWidth;
1836         }
1837         return width;
1838     },
1839
1840     isAncestor : function(p, c) {
1841         p = Roo.getDom(p);
1842         c = Roo.getDom(c);
1843         if (!p || !c) {
1844             return false;
1845         }
1846
1847         if (p.contains && !Roo.isSafari) {
1848             return p.contains(c);
1849         } else if (p.compareDocumentPosition) {
1850             return !!(p.compareDocumentPosition(c) & 16);
1851         } else {
1852             var parent = c.parentNode;
1853             while (parent) {
1854                 if (parent == p) {
1855                     return true;
1856                 }
1857                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858                     return false;
1859                 }
1860                 parent = parent.parentNode;
1861             }
1862             return false;
1863         }
1864     },
1865
1866     getRegion : function(el) {
1867         return Roo.lib.Region.getRegion(el);
1868     },
1869
1870     getY : function(el) {
1871         return this.getXY(el)[1];
1872     },
1873
1874     getX : function(el) {
1875         return this.getXY(el)[0];
1876     },
1877
1878     getXY : function(el) {
1879         var p, pe, b, scroll, bd = document.body;
1880         el = Roo.getDom(el);
1881         var fly = Roo.lib.AnimBase.fly;
1882         if (el.getBoundingClientRect) {
1883             b = el.getBoundingClientRect();
1884             scroll = fly(document).getScroll();
1885             return [b.left + scroll.left, b.top + scroll.top];
1886         }
1887         var x = 0, y = 0;
1888
1889         p = el;
1890
1891         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1892
1893         while (p) {
1894
1895             x += p.offsetLeft;
1896             y += p.offsetTop;
1897
1898             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1899                 hasAbsolute = true;
1900             }
1901
1902             if (Roo.isGecko) {
1903                 pe = fly(p);
1904
1905                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1907
1908
1909                 x += bl;
1910                 y += bt;
1911
1912
1913                 if (p != el && pe.getStyle('overflow') != 'visible') {
1914                     x += bl;
1915                     y += bt;
1916                 }
1917             }
1918             p = p.offsetParent;
1919         }
1920
1921         if (Roo.isSafari && hasAbsolute) {
1922             x -= bd.offsetLeft;
1923             y -= bd.offsetTop;
1924         }
1925
1926         if (Roo.isGecko && !hasAbsolute) {
1927             var dbd = fly(bd);
1928             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1930         }
1931
1932         p = el.parentNode;
1933         while (p && p != bd) {
1934             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1935                 x -= p.scrollLeft;
1936                 y -= p.scrollTop;
1937             }
1938             p = p.parentNode;
1939         }
1940         return [x, y];
1941     },
1942  
1943   
1944
1945
1946     setXY : function(el, xy) {
1947         el = Roo.fly(el, '_setXY');
1948         el.position();
1949         var pts = el.translatePoints(xy);
1950         if (xy[0] !== false) {
1951             el.dom.style.left = pts.left + "px";
1952         }
1953         if (xy[1] !== false) {
1954             el.dom.style.top = pts.top + "px";
1955         }
1956     },
1957
1958     setX : function(el, x) {
1959         this.setXY(el, [x, false]);
1960     },
1961
1962     setY : function(el, y) {
1963         this.setXY(el, [false, y]);
1964     }
1965 };
1966 /*
1967  * Portions of this file are based on pieces of Yahoo User Interface Library
1968  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969  * YUI licensed under the BSD License:
1970  * http://developer.yahoo.net/yui/license.txt
1971  * <script type="text/javascript">
1972  *
1973  */
1974
1975 Roo.lib.Event = function() {
1976     var loadComplete = false;
1977     var listeners = [];
1978     var unloadListeners = [];
1979     var retryCount = 0;
1980     var onAvailStack = [];
1981     var counter = 0;
1982     var lastError = null;
1983
1984     return {
1985         POLL_RETRYS: 200,
1986         POLL_INTERVAL: 20,
1987         EL: 0,
1988         TYPE: 1,
1989         FN: 2,
1990         WFN: 3,
1991         OBJ: 3,
1992         ADJ_SCOPE: 4,
1993         _interval: null,
1994
1995         startInterval: function() {
1996             if (!this._interval) {
1997                 var self = this;
1998                 var callback = function() {
1999                     self._tryPreloadAttach();
2000                 };
2001                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2002
2003             }
2004         },
2005
2006         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007             onAvailStack.push({ id:         p_id,
2008                 fn:         p_fn,
2009                 obj:        p_obj,
2010                 override:   p_override,
2011                 checkReady: false    });
2012
2013             retryCount = this.POLL_RETRYS;
2014             this.startInterval();
2015         },
2016
2017
2018         addListener: function(el, eventName, fn) {
2019             el = Roo.getDom(el);
2020             if (!el || !fn) {
2021                 return false;
2022             }
2023
2024             if ("unload" == eventName) {
2025                 unloadListeners[unloadListeners.length] =
2026                 [el, eventName, fn];
2027                 return true;
2028             }
2029
2030             var wrappedFn = function(e) {
2031                 return fn(Roo.lib.Event.getEvent(e));
2032             };
2033
2034             var li = [el, eventName, fn, wrappedFn];
2035
2036             var index = listeners.length;
2037             listeners[index] = li;
2038
2039             this.doAdd(el, eventName, wrappedFn, false);
2040             return true;
2041
2042         },
2043
2044
2045         removeListener: function(el, eventName, fn) {
2046             var i, len;
2047
2048             el = Roo.getDom(el);
2049
2050             if(!fn) {
2051                 return this.purgeElement(el, false, eventName);
2052             }
2053
2054
2055             if ("unload" == eventName) {
2056
2057                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058                     var li = unloadListeners[i];
2059                     if (li &&
2060                         li[0] == el &&
2061                         li[1] == eventName &&
2062                         li[2] == fn) {
2063                         unloadListeners.splice(i, 1);
2064                         return true;
2065                     }
2066                 }
2067
2068                 return false;
2069             }
2070
2071             var cacheItem = null;
2072
2073
2074             var index = arguments[3];
2075
2076             if ("undefined" == typeof index) {
2077                 index = this._getCacheIndex(el, eventName, fn);
2078             }
2079
2080             if (index >= 0) {
2081                 cacheItem = listeners[index];
2082             }
2083
2084             if (!el || !cacheItem) {
2085                 return false;
2086             }
2087
2088             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2089
2090             delete listeners[index][this.WFN];
2091             delete listeners[index][this.FN];
2092             listeners.splice(index, 1);
2093
2094             return true;
2095
2096         },
2097
2098
2099         getTarget: function(ev, resolveTextNode) {
2100             ev = ev.browserEvent || ev;
2101             var t = ev.target || ev.srcElement;
2102             return this.resolveTextNode(t);
2103         },
2104
2105
2106         resolveTextNode: function(node) {
2107             if (Roo.isSafari && node && 3 == node.nodeType) {
2108                 return node.parentNode;
2109             } else {
2110                 return node;
2111             }
2112         },
2113
2114
2115         getPageX: function(ev) {
2116             ev = ev.browserEvent || ev;
2117             var x = ev.pageX;
2118             if (!x && 0 !== x) {
2119                 x = ev.clientX || 0;
2120
2121                 if (Roo.isIE) {
2122                     x += this.getScroll()[1];
2123                 }
2124             }
2125
2126             return x;
2127         },
2128
2129
2130         getPageY: function(ev) {
2131             ev = ev.browserEvent || ev;
2132             var y = ev.pageY;
2133             if (!y && 0 !== y) {
2134                 y = ev.clientY || 0;
2135
2136                 if (Roo.isIE) {
2137                     y += this.getScroll()[0];
2138                 }
2139             }
2140
2141
2142             return y;
2143         },
2144
2145
2146         getXY: function(ev) {
2147             ev = ev.browserEvent || ev;
2148             return [this.getPageX(ev), this.getPageY(ev)];
2149         },
2150
2151
2152         getRelatedTarget: function(ev) {
2153             ev = ev.browserEvent || ev;
2154             var t = ev.relatedTarget;
2155             if (!t) {
2156                 if (ev.type == "mouseout") {
2157                     t = ev.toElement;
2158                 } else if (ev.type == "mouseover") {
2159                     t = ev.fromElement;
2160                 }
2161             }
2162
2163             return this.resolveTextNode(t);
2164         },
2165
2166
2167         getTime: function(ev) {
2168             ev = ev.browserEvent || ev;
2169             if (!ev.time) {
2170                 var t = new Date().getTime();
2171                 try {
2172                     ev.time = t;
2173                 } catch(ex) {
2174                     this.lastError = ex;
2175                     return t;
2176                 }
2177             }
2178
2179             return ev.time;
2180         },
2181
2182
2183         stopEvent: function(ev) {
2184             this.stopPropagation(ev);
2185             this.preventDefault(ev);
2186         },
2187
2188
2189         stopPropagation: function(ev) {
2190             ev = ev.browserEvent || ev;
2191             if (ev.stopPropagation) {
2192                 ev.stopPropagation();
2193             } else {
2194                 ev.cancelBubble = true;
2195             }
2196         },
2197
2198
2199         preventDefault: function(ev) {
2200             ev = ev.browserEvent || ev;
2201             if(ev.preventDefault) {
2202                 ev.preventDefault();
2203             } else {
2204                 ev.returnValue = false;
2205             }
2206         },
2207
2208
2209         getEvent: function(e) {
2210             var ev = e || window.event;
2211             if (!ev) {
2212                 var c = this.getEvent.caller;
2213                 while (c) {
2214                     ev = c.arguments[0];
2215                     if (ev && Event == ev.constructor) {
2216                         break;
2217                     }
2218                     c = c.caller;
2219                 }
2220             }
2221             return ev;
2222         },
2223
2224
2225         getCharCode: function(ev) {
2226             ev = ev.browserEvent || ev;
2227             return ev.charCode || ev.keyCode || 0;
2228         },
2229
2230
2231         _getCacheIndex: function(el, eventName, fn) {
2232             for (var i = 0,len = listeners.length; i < len; ++i) {
2233                 var li = listeners[i];
2234                 if (li &&
2235                     li[this.FN] == fn &&
2236                     li[this.EL] == el &&
2237                     li[this.TYPE] == eventName) {
2238                     return i;
2239                 }
2240             }
2241
2242             return -1;
2243         },
2244
2245
2246         elCache: {},
2247
2248
2249         getEl: function(id) {
2250             return document.getElementById(id);
2251         },
2252
2253
2254         clearCache: function() {
2255         },
2256
2257
2258         _load: function(e) {
2259             loadComplete = true;
2260             var EU = Roo.lib.Event;
2261
2262
2263             if (Roo.isIE) {
2264                 EU.doRemove(window, "load", EU._load);
2265             }
2266         },
2267
2268
2269         _tryPreloadAttach: function() {
2270
2271             if (this.locked) {
2272                 return false;
2273             }
2274
2275             this.locked = true;
2276
2277
2278             var tryAgain = !loadComplete;
2279             if (!tryAgain) {
2280                 tryAgain = (retryCount > 0);
2281             }
2282
2283
2284             var notAvail = [];
2285             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2286                 var item = onAvailStack[i];
2287                 if (item) {
2288                     var el = this.getEl(item.id);
2289
2290                     if (el) {
2291                         if (!item.checkReady ||
2292                             loadComplete ||
2293                             el.nextSibling ||
2294                             (document && document.body)) {
2295
2296                             var scope = el;
2297                             if (item.override) {
2298                                 if (item.override === true) {
2299                                     scope = item.obj;
2300                                 } else {
2301                                     scope = item.override;
2302                                 }
2303                             }
2304                             item.fn.call(scope, item.obj);
2305                             onAvailStack[i] = null;
2306                         }
2307                     } else {
2308                         notAvail.push(item);
2309                     }
2310                 }
2311             }
2312
2313             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2314
2315             if (tryAgain) {
2316
2317                 this.startInterval();
2318             } else {
2319                 clearInterval(this._interval);
2320                 this._interval = null;
2321             }
2322
2323             this.locked = false;
2324
2325             return true;
2326
2327         },
2328
2329
2330         purgeElement: function(el, recurse, eventName) {
2331             var elListeners = this.getListeners(el, eventName);
2332             if (elListeners) {
2333                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2334                     var l = elListeners[i];
2335                     this.removeListener(el, l.type, l.fn);
2336                 }
2337             }
2338
2339             if (recurse && el && el.childNodes) {
2340                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2341                     this.purgeElement(el.childNodes[i], recurse, eventName);
2342                 }
2343             }
2344         },
2345
2346
2347         getListeners: function(el, eventName) {
2348             var results = [], searchLists;
2349             if (!eventName) {
2350                 searchLists = [listeners, unloadListeners];
2351             } else if (eventName == "unload") {
2352                 searchLists = [unloadListeners];
2353             } else {
2354                 searchLists = [listeners];
2355             }
2356
2357             for (var j = 0; j < searchLists.length; ++j) {
2358                 var searchList = searchLists[j];
2359                 if (searchList && searchList.length > 0) {
2360                     for (var i = 0,len = searchList.length; i < len; ++i) {
2361                         var l = searchList[i];
2362                         if (l && l[this.EL] === el &&
2363                             (!eventName || eventName === l[this.TYPE])) {
2364                             results.push({
2365                                 type:   l[this.TYPE],
2366                                 fn:     l[this.FN],
2367                                 obj:    l[this.OBJ],
2368                                 adjust: l[this.ADJ_SCOPE],
2369                                 index:  i
2370                             });
2371                         }
2372                     }
2373                 }
2374             }
2375
2376             return (results.length) ? results : null;
2377         },
2378
2379
2380         _unload: function(e) {
2381
2382             var EU = Roo.lib.Event, i, j, l, len, index;
2383
2384             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2385                 l = unloadListeners[i];
2386                 if (l) {
2387                     var scope = window;
2388                     if (l[EU.ADJ_SCOPE]) {
2389                         if (l[EU.ADJ_SCOPE] === true) {
2390                             scope = l[EU.OBJ];
2391                         } else {
2392                             scope = l[EU.ADJ_SCOPE];
2393                         }
2394                     }
2395                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2396                     unloadListeners[i] = null;
2397                     l = null;
2398                     scope = null;
2399                 }
2400             }
2401
2402             unloadListeners = null;
2403
2404             if (listeners && listeners.length > 0) {
2405                 j = listeners.length;
2406                 while (j) {
2407                     index = j - 1;
2408                     l = listeners[index];
2409                     if (l) {
2410                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2411                                 l[EU.FN], index);
2412                     }
2413                     j = j - 1;
2414                 }
2415                 l = null;
2416
2417                 EU.clearCache();
2418             }
2419
2420             EU.doRemove(window, "unload", EU._unload);
2421
2422         },
2423
2424
2425         getScroll: function() {
2426             var dd = document.documentElement, db = document.body;
2427             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2428                 return [dd.scrollTop, dd.scrollLeft];
2429             } else if (db) {
2430                 return [db.scrollTop, db.scrollLeft];
2431             } else {
2432                 return [0, 0];
2433             }
2434         },
2435
2436
2437         doAdd: function () {
2438             if (window.addEventListener) {
2439                 return function(el, eventName, fn, capture) {
2440                     el.addEventListener(eventName, fn, (capture));
2441                 };
2442             } else if (window.attachEvent) {
2443                 return function(el, eventName, fn, capture) {
2444                     el.attachEvent("on" + eventName, fn);
2445                 };
2446             } else {
2447                 return function() {
2448                 };
2449             }
2450         }(),
2451
2452
2453         doRemove: function() {
2454             if (window.removeEventListener) {
2455                 return function (el, eventName, fn, capture) {
2456                     el.removeEventListener(eventName, fn, (capture));
2457                 };
2458             } else if (window.detachEvent) {
2459                 return function (el, eventName, fn) {
2460                     el.detachEvent("on" + eventName, fn);
2461                 };
2462             } else {
2463                 return function() {
2464                 };
2465             }
2466         }()
2467     };
2468     
2469 }();
2470 (function() {     
2471    
2472     var E = Roo.lib.Event;
2473     E.on = E.addListener;
2474     E.un = E.removeListener;
2475
2476     if (document && document.body) {
2477         E._load();
2478     } else {
2479         E.doAdd(window, "load", E._load);
2480     }
2481     E.doAdd(window, "unload", E._unload);
2482     E._tryPreloadAttach();
2483 })();
2484
2485 /*
2486  * Portions of this file are based on pieces of Yahoo User Interface Library
2487  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2488  * YUI licensed under the BSD License:
2489  * http://developer.yahoo.net/yui/license.txt
2490  * <script type="text/javascript">
2491  *
2492  */
2493
2494 (function() {
2495     /**
2496      * @class Roo.lib.Ajax
2497      *
2498      */
2499     Roo.lib.Ajax = {
2500         /**
2501          * @static 
2502          */
2503         request : function(method, uri, cb, data, options) {
2504             if(options){
2505                 var hs = options.headers;
2506                 if(hs){
2507                     for(var h in hs){
2508                         if(hs.hasOwnProperty(h)){
2509                             this.initHeader(h, hs[h], false);
2510                         }
2511                     }
2512                 }
2513                 if(options.xmlData){
2514                     this.initHeader('Content-Type', 'text/xml', false);
2515                     method = 'POST';
2516                     data = options.xmlData;
2517                 }
2518             }
2519
2520             return this.asyncRequest(method, uri, cb, data);
2521         },
2522
2523         serializeForm : function(form) {
2524             if(typeof form == 'string') {
2525                 form = (document.getElementById(form) || document.forms[form]);
2526             }
2527
2528             var el, name, val, disabled, data = '', hasSubmit = false;
2529             for (var i = 0; i < form.elements.length; i++) {
2530                 el = form.elements[i];
2531                 disabled = form.elements[i].disabled;
2532                 name = form.elements[i].name;
2533                 val = form.elements[i].value;
2534
2535                 if (!disabled && name){
2536                     switch (el.type)
2537                             {
2538                         case 'select-one':
2539                         case 'select-multiple':
2540                             for (var j = 0; j < el.options.length; j++) {
2541                                 if (el.options[j].selected) {
2542                                     if (Roo.isIE) {
2543                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2544                                     }
2545                                     else {
2546                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2547                                     }
2548                                 }
2549                             }
2550                             break;
2551                         case 'radio':
2552                         case 'checkbox':
2553                             if (el.checked) {
2554                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2555                             }
2556                             break;
2557                         case 'file':
2558
2559                         case undefined:
2560
2561                         case 'reset':
2562
2563                         case 'button':
2564
2565                             break;
2566                         case 'submit':
2567                             if(hasSubmit == false) {
2568                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2569                                 hasSubmit = true;
2570                             }
2571                             break;
2572                         default:
2573                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2574                             break;
2575                     }
2576                 }
2577             }
2578             data = data.substr(0, data.length - 1);
2579             return data;
2580         },
2581
2582         headers:{},
2583
2584         hasHeaders:false,
2585
2586         useDefaultHeader:true,
2587
2588         defaultPostHeader:'application/x-www-form-urlencoded',
2589
2590         useDefaultXhrHeader:true,
2591
2592         defaultXhrHeader:'XMLHttpRequest',
2593
2594         hasDefaultHeaders:true,
2595
2596         defaultHeaders:{},
2597
2598         poll:{},
2599
2600         timeout:{},
2601
2602         pollInterval:50,
2603
2604         transactionId:0,
2605
2606         setProgId:function(id)
2607         {
2608             this.activeX.unshift(id);
2609         },
2610
2611         setDefaultPostHeader:function(b)
2612         {
2613             this.useDefaultHeader = b;
2614         },
2615
2616         setDefaultXhrHeader:function(b)
2617         {
2618             this.useDefaultXhrHeader = b;
2619         },
2620
2621         setPollingInterval:function(i)
2622         {
2623             if (typeof i == 'number' && isFinite(i)) {
2624                 this.pollInterval = i;
2625             }
2626         },
2627
2628         createXhrObject:function(transactionId)
2629         {
2630             var obj,http;
2631             try
2632             {
2633
2634                 http = new XMLHttpRequest();
2635
2636                 obj = { conn:http, tId:transactionId };
2637             }
2638             catch(e)
2639             {
2640                 for (var i = 0; i < this.activeX.length; ++i) {
2641                     try
2642                     {
2643
2644                         http = new ActiveXObject(this.activeX[i]);
2645
2646                         obj = { conn:http, tId:transactionId };
2647                         break;
2648                     }
2649                     catch(e) {
2650                     }
2651                 }
2652             }
2653             finally
2654             {
2655                 return obj;
2656             }
2657         },
2658
2659         getConnectionObject:function()
2660         {
2661             var o;
2662             var tId = this.transactionId;
2663
2664             try
2665             {
2666                 o = this.createXhrObject(tId);
2667                 if (o) {
2668                     this.transactionId++;
2669                 }
2670             }
2671             catch(e) {
2672             }
2673             finally
2674             {
2675                 return o;
2676             }
2677         },
2678
2679         asyncRequest:function(method, uri, callback, postData)
2680         {
2681             var o = this.getConnectionObject();
2682
2683             if (!o) {
2684                 return null;
2685             }
2686             else {
2687                 o.conn.open(method, uri, true);
2688
2689                 if (this.useDefaultXhrHeader) {
2690                     if (!this.defaultHeaders['X-Requested-With']) {
2691                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2692                     }
2693                 }
2694
2695                 if(postData && this.useDefaultHeader){
2696                     this.initHeader('Content-Type', this.defaultPostHeader);
2697                 }
2698
2699                  if (this.hasDefaultHeaders || this.hasHeaders) {
2700                     this.setHeader(o);
2701                 }
2702
2703                 this.handleReadyState(o, callback);
2704                 o.conn.send(postData || null);
2705
2706                 return o;
2707             }
2708         },
2709
2710         handleReadyState:function(o, callback)
2711         {
2712             var oConn = this;
2713
2714             if (callback && callback.timeout) {
2715                 
2716                 this.timeout[o.tId] = window.setTimeout(function() {
2717                     oConn.abort(o, callback, true);
2718                 }, callback.timeout);
2719             }
2720
2721             this.poll[o.tId] = window.setInterval(
2722                     function() {
2723                         if (o.conn && o.conn.readyState == 4) {
2724                             window.clearInterval(oConn.poll[o.tId]);
2725                             delete oConn.poll[o.tId];
2726
2727                             if(callback && callback.timeout) {
2728                                 window.clearTimeout(oConn.timeout[o.tId]);
2729                                 delete oConn.timeout[o.tId];
2730                             }
2731
2732                             oConn.handleTransactionResponse(o, callback);
2733                         }
2734                     }
2735                     , this.pollInterval);
2736         },
2737
2738         handleTransactionResponse:function(o, callback, isAbort)
2739         {
2740
2741             if (!callback) {
2742                 this.releaseObject(o);
2743                 return;
2744             }
2745
2746             var httpStatus, responseObject;
2747
2748             try
2749             {
2750                 if (o.conn.status !== undefined && o.conn.status != 0) {
2751                     httpStatus = o.conn.status;
2752                 }
2753                 else {
2754                     httpStatus = 13030;
2755                 }
2756             }
2757             catch(e) {
2758
2759
2760                 httpStatus = 13030;
2761             }
2762
2763             if (httpStatus >= 200 && httpStatus < 300) {
2764                 responseObject = this.createResponseObject(o, callback.argument);
2765                 if (callback.success) {
2766                     if (!callback.scope) {
2767                         callback.success(responseObject);
2768                     }
2769                     else {
2770
2771
2772                         callback.success.apply(callback.scope, [responseObject]);
2773                     }
2774                 }
2775             }
2776             else {
2777                 switch (httpStatus) {
2778
2779                     case 12002:
2780                     case 12029:
2781                     case 12030:
2782                     case 12031:
2783                     case 12152:
2784                     case 13030:
2785                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2786                         if (callback.failure) {
2787                             if (!callback.scope) {
2788                                 callback.failure(responseObject);
2789                             }
2790                             else {
2791                                 callback.failure.apply(callback.scope, [responseObject]);
2792                             }
2793                         }
2794                         break;
2795                     default:
2796                         responseObject = this.createResponseObject(o, callback.argument);
2797                         if (callback.failure) {
2798                             if (!callback.scope) {
2799                                 callback.failure(responseObject);
2800                             }
2801                             else {
2802                                 callback.failure.apply(callback.scope, [responseObject]);
2803                             }
2804                         }
2805                 }
2806             }
2807
2808             this.releaseObject(o);
2809             responseObject = null;
2810         },
2811
2812         createResponseObject:function(o, callbackArg)
2813         {
2814             var obj = {};
2815             var headerObj = {};
2816
2817             try
2818             {
2819                 var headerStr = o.conn.getAllResponseHeaders();
2820                 var header = headerStr.split('\n');
2821                 for (var i = 0; i < header.length; i++) {
2822                     var delimitPos = header[i].indexOf(':');
2823                     if (delimitPos != -1) {
2824                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2825                     }
2826                 }
2827             }
2828             catch(e) {
2829             }
2830
2831             obj.tId = o.tId;
2832             obj.status = o.conn.status;
2833             obj.statusText = o.conn.statusText;
2834             obj.getResponseHeader = headerObj;
2835             obj.getAllResponseHeaders = headerStr;
2836             obj.responseText = o.conn.responseText;
2837             obj.responseXML = o.conn.responseXML;
2838
2839             if (typeof callbackArg !== undefined) {
2840                 obj.argument = callbackArg;
2841             }
2842
2843             return obj;
2844         },
2845
2846         createExceptionObject:function(tId, callbackArg, isAbort)
2847         {
2848             var COMM_CODE = 0;
2849             var COMM_ERROR = 'communication failure';
2850             var ABORT_CODE = -1;
2851             var ABORT_ERROR = 'transaction aborted';
2852
2853             var obj = {};
2854
2855             obj.tId = tId;
2856             if (isAbort) {
2857                 obj.status = ABORT_CODE;
2858                 obj.statusText = ABORT_ERROR;
2859             }
2860             else {
2861                 obj.status = COMM_CODE;
2862                 obj.statusText = COMM_ERROR;
2863             }
2864
2865             if (callbackArg) {
2866                 obj.argument = callbackArg;
2867             }
2868
2869             return obj;
2870         },
2871
2872         initHeader:function(label, value, isDefault)
2873         {
2874             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2875
2876             if (headerObj[label] === undefined) {
2877                 headerObj[label] = value;
2878             }
2879             else {
2880
2881
2882                 headerObj[label] = value + "," + headerObj[label];
2883             }
2884
2885             if (isDefault) {
2886                 this.hasDefaultHeaders = true;
2887             }
2888             else {
2889                 this.hasHeaders = true;
2890             }
2891         },
2892
2893
2894         setHeader:function(o)
2895         {
2896             if (this.hasDefaultHeaders) {
2897                 for (var prop in this.defaultHeaders) {
2898                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2899                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2900                     }
2901                 }
2902             }
2903
2904             if (this.hasHeaders) {
2905                 for (var prop in this.headers) {
2906                     if (this.headers.hasOwnProperty(prop)) {
2907                         o.conn.setRequestHeader(prop, this.headers[prop]);
2908                     }
2909                 }
2910                 this.headers = {};
2911                 this.hasHeaders = false;
2912             }
2913         },
2914
2915         resetDefaultHeaders:function() {
2916             delete this.defaultHeaders;
2917             this.defaultHeaders = {};
2918             this.hasDefaultHeaders = false;
2919         },
2920
2921         abort:function(o, callback, isTimeout)
2922         {
2923             if(this.isCallInProgress(o)) {
2924                 o.conn.abort();
2925                 window.clearInterval(this.poll[o.tId]);
2926                 delete this.poll[o.tId];
2927                 if (isTimeout) {
2928                     delete this.timeout[o.tId];
2929                 }
2930
2931                 this.handleTransactionResponse(o, callback, true);
2932
2933                 return true;
2934             }
2935             else {
2936                 return false;
2937             }
2938         },
2939
2940
2941         isCallInProgress:function(o)
2942         {
2943             if (o && o.conn) {
2944                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2945             }
2946             else {
2947
2948                 return false;
2949             }
2950         },
2951
2952
2953         releaseObject:function(o)
2954         {
2955
2956             o.conn = null;
2957
2958             o = null;
2959         },
2960
2961         activeX:[
2962         'MSXML2.XMLHTTP.3.0',
2963         'MSXML2.XMLHTTP',
2964         'Microsoft.XMLHTTP'
2965         ]
2966
2967
2968     };
2969 })();/*
2970  * Portions of this file are based on pieces of Yahoo User Interface Library
2971  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2972  * YUI licensed under the BSD License:
2973  * http://developer.yahoo.net/yui/license.txt
2974  * <script type="text/javascript">
2975  *
2976  */
2977
2978 Roo.lib.Region = function(t, r, b, l) {
2979     this.top = t;
2980     this[1] = t;
2981     this.right = r;
2982     this.bottom = b;
2983     this.left = l;
2984     this[0] = l;
2985 };
2986
2987
2988 Roo.lib.Region.prototype = {
2989     contains : function(region) {
2990         return ( region.left >= this.left &&
2991                  region.right <= this.right &&
2992                  region.top >= this.top &&
2993                  region.bottom <= this.bottom    );
2994
2995     },
2996
2997     getArea : function() {
2998         return ( (this.bottom - this.top) * (this.right - this.left) );
2999     },
3000
3001     intersect : function(region) {
3002         var t = Math.max(this.top, region.top);
3003         var r = Math.min(this.right, region.right);
3004         var b = Math.min(this.bottom, region.bottom);
3005         var l = Math.max(this.left, region.left);
3006
3007         if (b >= t && r >= l) {
3008             return new Roo.lib.Region(t, r, b, l);
3009         } else {
3010             return null;
3011         }
3012     },
3013     union : function(region) {
3014         var t = Math.min(this.top, region.top);
3015         var r = Math.max(this.right, region.right);
3016         var b = Math.max(this.bottom, region.bottom);
3017         var l = Math.min(this.left, region.left);
3018
3019         return new Roo.lib.Region(t, r, b, l);
3020     },
3021
3022     adjust : function(t, l, b, r) {
3023         this.top += t;
3024         this.left += l;
3025         this.right += r;
3026         this.bottom += b;
3027         return this;
3028     }
3029 };
3030
3031 Roo.lib.Region.getRegion = function(el) {
3032     var p = Roo.lib.Dom.getXY(el);
3033
3034     var t = p[1];
3035     var r = p[0] + el.offsetWidth;
3036     var b = p[1] + el.offsetHeight;
3037     var l = p[0];
3038
3039     return new Roo.lib.Region(t, r, b, l);
3040 };
3041 /*
3042  * Portions of this file are based on pieces of Yahoo User Interface Library
3043  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3044  * YUI licensed under the BSD License:
3045  * http://developer.yahoo.net/yui/license.txt
3046  * <script type="text/javascript">
3047  *
3048  */
3049 //@@dep Roo.lib.Region
3050
3051
3052 Roo.lib.Point = function(x, y) {
3053     if (x instanceof Array) {
3054         y = x[1];
3055         x = x[0];
3056     }
3057     this.x = this.right = this.left = this[0] = x;
3058     this.y = this.top = this.bottom = this[1] = y;
3059 };
3060
3061 Roo.lib.Point.prototype = new Roo.lib.Region();
3062 /*
3063  * Portions of this file are based on pieces of Yahoo User Interface Library
3064  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3065  * YUI licensed under the BSD License:
3066  * http://developer.yahoo.net/yui/license.txt
3067  * <script type="text/javascript">
3068  *
3069  */
3070  
3071 (function() {   
3072
3073     Roo.lib.Anim = {
3074         scroll : function(el, args, duration, easing, cb, scope) {
3075             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3076         },
3077
3078         motion : function(el, args, duration, easing, cb, scope) {
3079             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3080         },
3081
3082         color : function(el, args, duration, easing, cb, scope) {
3083             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3084         },
3085
3086         run : function(el, args, duration, easing, cb, scope, type) {
3087             type = type || Roo.lib.AnimBase;
3088             if (typeof easing == "string") {
3089                 easing = Roo.lib.Easing[easing];
3090             }
3091             var anim = new type(el, args, duration, easing);
3092             anim.animateX(function() {
3093                 Roo.callback(cb, scope);
3094             });
3095             return anim;
3096         }
3097     };
3098 })();/*
3099  * Portions of this file are based on pieces of Yahoo User Interface Library
3100  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3101  * YUI licensed under the BSD License:
3102  * http://developer.yahoo.net/yui/license.txt
3103  * <script type="text/javascript">
3104  *
3105  */
3106
3107 (function() {    
3108     var libFlyweight;
3109     
3110     function fly(el) {
3111         if (!libFlyweight) {
3112             libFlyweight = new Roo.Element.Flyweight();
3113         }
3114         libFlyweight.dom = el;
3115         return libFlyweight;
3116     }
3117
3118     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3119     
3120    
3121     
3122     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3123         if (el) {
3124             this.init(el, attributes, duration, method);
3125         }
3126     };
3127
3128     Roo.lib.AnimBase.fly = fly;
3129     
3130     
3131     
3132     Roo.lib.AnimBase.prototype = {
3133
3134         toString: function() {
3135             var el = this.getEl();
3136             var id = el.id || el.tagName;
3137             return ("Anim " + id);
3138         },
3139
3140         patterns: {
3141             noNegatives:        /width|height|opacity|padding/i,
3142             offsetAttribute:  /^((width|height)|(top|left))$/,
3143             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3144             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3145         },
3146
3147
3148         doMethod: function(attr, start, end) {
3149             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3150         },
3151
3152
3153         setAttribute: function(attr, val, unit) {
3154             if (this.patterns.noNegatives.test(attr)) {
3155                 val = (val > 0) ? val : 0;
3156             }
3157
3158             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3159         },
3160
3161
3162         getAttribute: function(attr) {
3163             var el = this.getEl();
3164             var val = fly(el).getStyle(attr);
3165
3166             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3167                 return parseFloat(val);
3168             }
3169
3170             var a = this.patterns.offsetAttribute.exec(attr) || [];
3171             var pos = !!( a[3] );
3172             var box = !!( a[2] );
3173
3174
3175             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3176                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3177             } else {
3178                 val = 0;
3179             }
3180
3181             return val;
3182         },
3183
3184
3185         getDefaultUnit: function(attr) {
3186             if (this.patterns.defaultUnit.test(attr)) {
3187                 return 'px';
3188             }
3189
3190             return '';
3191         },
3192
3193         animateX : function(callback, scope) {
3194             var f = function() {
3195                 this.onComplete.removeListener(f);
3196                 if (typeof callback == "function") {
3197                     callback.call(scope || this, this);
3198                 }
3199             };
3200             this.onComplete.addListener(f, this);
3201             this.animate();
3202         },
3203
3204
3205         setRuntimeAttribute: function(attr) {
3206             var start;
3207             var end;
3208             var attributes = this.attributes;
3209
3210             this.runtimeAttributes[attr] = {};
3211
3212             var isset = function(prop) {
3213                 return (typeof prop !== 'undefined');
3214             };
3215
3216             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3217                 return false;
3218             }
3219
3220             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3221
3222
3223             if (isset(attributes[attr]['to'])) {
3224                 end = attributes[attr]['to'];
3225             } else if (isset(attributes[attr]['by'])) {
3226                 if (start.constructor == Array) {
3227                     end = [];
3228                     for (var i = 0, len = start.length; i < len; ++i) {
3229                         end[i] = start[i] + attributes[attr]['by'][i];
3230                     }
3231                 } else {
3232                     end = start + attributes[attr]['by'];
3233                 }
3234             }
3235
3236             this.runtimeAttributes[attr].start = start;
3237             this.runtimeAttributes[attr].end = end;
3238
3239
3240             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3241         },
3242
3243
3244         init: function(el, attributes, duration, method) {
3245
3246             var isAnimated = false;
3247
3248
3249             var startTime = null;
3250
3251
3252             var actualFrames = 0;
3253
3254
3255             el = Roo.getDom(el);
3256
3257
3258             this.attributes = attributes || {};
3259
3260
3261             this.duration = duration || 1;
3262
3263
3264             this.method = method || Roo.lib.Easing.easeNone;
3265
3266
3267             this.useSeconds = true;
3268
3269
3270             this.currentFrame = 0;
3271
3272
3273             this.totalFrames = Roo.lib.AnimMgr.fps;
3274
3275
3276             this.getEl = function() {
3277                 return el;
3278             };
3279
3280
3281             this.isAnimated = function() {
3282                 return isAnimated;
3283             };
3284
3285
3286             this.getStartTime = function() {
3287                 return startTime;
3288             };
3289
3290             this.runtimeAttributes = {};
3291
3292
3293             this.animate = function() {
3294                 if (this.isAnimated()) {
3295                     return false;
3296                 }
3297
3298                 this.currentFrame = 0;
3299
3300                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3301
3302                 Roo.lib.AnimMgr.registerElement(this);
3303             };
3304
3305
3306             this.stop = function(finish) {
3307                 if (finish) {
3308                     this.currentFrame = this.totalFrames;
3309                     this._onTween.fire();
3310                 }
3311                 Roo.lib.AnimMgr.stop(this);
3312             };
3313
3314             var onStart = function() {
3315                 this.onStart.fire();
3316
3317                 this.runtimeAttributes = {};
3318                 for (var attr in this.attributes) {
3319                     this.setRuntimeAttribute(attr);
3320                 }
3321
3322                 isAnimated = true;
3323                 actualFrames = 0;
3324                 startTime = new Date();
3325             };
3326
3327
3328             var onTween = function() {
3329                 var data = {
3330                     duration: new Date() - this.getStartTime(),
3331                     currentFrame: this.currentFrame
3332                 };
3333
3334                 data.toString = function() {
3335                     return (
3336                             'duration: ' + data.duration +
3337                             ', currentFrame: ' + data.currentFrame
3338                             );
3339                 };
3340
3341                 this.onTween.fire(data);
3342
3343                 var runtimeAttributes = this.runtimeAttributes;
3344
3345                 for (var attr in runtimeAttributes) {
3346                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3347                 }
3348
3349                 actualFrames += 1;
3350             };
3351
3352             var onComplete = function() {
3353                 var actual_duration = (new Date() - startTime) / 1000 ;
3354
3355                 var data = {
3356                     duration: actual_duration,
3357                     frames: actualFrames,
3358                     fps: actualFrames / actual_duration
3359                 };
3360
3361                 data.toString = function() {
3362                     return (
3363                             'duration: ' + data.duration +
3364                             ', frames: ' + data.frames +
3365                             ', fps: ' + data.fps
3366                             );
3367                 };
3368
3369                 isAnimated = false;
3370                 actualFrames = 0;
3371                 this.onComplete.fire(data);
3372             };
3373
3374
3375             this._onStart = new Roo.util.Event(this);
3376             this.onStart = new Roo.util.Event(this);
3377             this.onTween = new Roo.util.Event(this);
3378             this._onTween = new Roo.util.Event(this);
3379             this.onComplete = new Roo.util.Event(this);
3380             this._onComplete = new Roo.util.Event(this);
3381             this._onStart.addListener(onStart);
3382             this._onTween.addListener(onTween);
3383             this._onComplete.addListener(onComplete);
3384         }
3385     };
3386 })();
3387 /*
3388  * Portions of this file are based on pieces of Yahoo User Interface Library
3389  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3390  * YUI licensed under the BSD License:
3391  * http://developer.yahoo.net/yui/license.txt
3392  * <script type="text/javascript">
3393  *
3394  */
3395
3396 Roo.lib.AnimMgr = new function() {
3397
3398         var thread = null;
3399
3400
3401         var queue = [];
3402
3403
3404         var tweenCount = 0;
3405
3406
3407         this.fps = 1000;
3408
3409
3410         this.delay = 1;
3411
3412
3413         this.registerElement = function(tween) {
3414             queue[queue.length] = tween;
3415             tweenCount += 1;
3416             tween._onStart.fire();
3417             this.start();
3418         };
3419
3420
3421         this.unRegister = function(tween, index) {
3422             tween._onComplete.fire();
3423             index = index || getIndex(tween);
3424             if (index != -1) {
3425                 queue.splice(index, 1);
3426             }
3427
3428             tweenCount -= 1;
3429             if (tweenCount <= 0) {
3430                 this.stop();
3431             }
3432         };
3433
3434
3435         this.start = function() {
3436             if (thread === null) {
3437                 thread = setInterval(this.run, this.delay);
3438             }
3439         };
3440
3441
3442         this.stop = function(tween) {
3443             if (!tween) {
3444                 clearInterval(thread);
3445
3446                 for (var i = 0, len = queue.length; i < len; ++i) {
3447                     if (queue[0].isAnimated()) {
3448                         this.unRegister(queue[0], 0);
3449                     }
3450                 }
3451
3452                 queue = [];
3453                 thread = null;
3454                 tweenCount = 0;
3455             }
3456             else {
3457                 this.unRegister(tween);
3458             }
3459         };
3460
3461
3462         this.run = function() {
3463             for (var i = 0, len = queue.length; i < len; ++i) {
3464                 var tween = queue[i];
3465                 if (!tween || !tween.isAnimated()) {
3466                     continue;
3467                 }
3468
3469                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3470                 {
3471                     tween.currentFrame += 1;
3472
3473                     if (tween.useSeconds) {
3474                         correctFrame(tween);
3475                     }
3476                     tween._onTween.fire();
3477                 }
3478                 else {
3479                     Roo.lib.AnimMgr.stop(tween, i);
3480                 }
3481             }
3482         };
3483
3484         var getIndex = function(anim) {
3485             for (var i = 0, len = queue.length; i < len; ++i) {
3486                 if (queue[i] == anim) {
3487                     return i;
3488                 }
3489             }
3490             return -1;
3491         };
3492
3493
3494         var correctFrame = function(tween) {
3495             var frames = tween.totalFrames;
3496             var frame = tween.currentFrame;
3497             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3498             var elapsed = (new Date() - tween.getStartTime());
3499             var tweak = 0;
3500
3501             if (elapsed < tween.duration * 1000) {
3502                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3503             } else {
3504                 tweak = frames - (frame + 1);
3505             }
3506             if (tweak > 0 && isFinite(tweak)) {
3507                 if (tween.currentFrame + tweak >= frames) {
3508                     tweak = frames - (frame + 1);
3509                 }
3510
3511                 tween.currentFrame += tweak;
3512             }
3513         };
3514     };/*
3515  * Portions of this file are based on pieces of Yahoo User Interface Library
3516  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3517  * YUI licensed under the BSD License:
3518  * http://developer.yahoo.net/yui/license.txt
3519  * <script type="text/javascript">
3520  *
3521  */
3522 Roo.lib.Bezier = new function() {
3523
3524         this.getPosition = function(points, t) {
3525             var n = points.length;
3526             var tmp = [];
3527
3528             for (var i = 0; i < n; ++i) {
3529                 tmp[i] = [points[i][0], points[i][1]];
3530             }
3531
3532             for (var j = 1; j < n; ++j) {
3533                 for (i = 0; i < n - j; ++i) {
3534                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3535                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3536                 }
3537             }
3538
3539             return [ tmp[0][0], tmp[0][1] ];
3540
3541         };
3542     };/*
3543  * Portions of this file are based on pieces of Yahoo User Interface Library
3544  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545  * YUI licensed under the BSD License:
3546  * http://developer.yahoo.net/yui/license.txt
3547  * <script type="text/javascript">
3548  *
3549  */
3550 (function() {
3551
3552     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3553         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3554     };
3555
3556     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3557
3558     var fly = Roo.lib.AnimBase.fly;
3559     var Y = Roo.lib;
3560     var superclass = Y.ColorAnim.superclass;
3561     var proto = Y.ColorAnim.prototype;
3562
3563     proto.toString = function() {
3564         var el = this.getEl();
3565         var id = el.id || el.tagName;
3566         return ("ColorAnim " + id);
3567     };
3568
3569     proto.patterns.color = /color$/i;
3570     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3571     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3572     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3573     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3574
3575
3576     proto.parseColor = function(s) {
3577         if (s.length == 3) {
3578             return s;
3579         }
3580
3581         var c = this.patterns.hex.exec(s);
3582         if (c && c.length == 4) {
3583             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3584         }
3585
3586         c = this.patterns.rgb.exec(s);
3587         if (c && c.length == 4) {
3588             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3589         }
3590
3591         c = this.patterns.hex3.exec(s);
3592         if (c && c.length == 4) {
3593             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3594         }
3595
3596         return null;
3597     };
3598     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3599     proto.getAttribute = function(attr) {
3600         var el = this.getEl();
3601         if (this.patterns.color.test(attr)) {
3602             var val = fly(el).getStyle(attr);
3603
3604             if (this.patterns.transparent.test(val)) {
3605                 var parent = el.parentNode;
3606                 val = fly(parent).getStyle(attr);
3607
3608                 while (parent && this.patterns.transparent.test(val)) {
3609                     parent = parent.parentNode;
3610                     val = fly(parent).getStyle(attr);
3611                     if (parent.tagName.toUpperCase() == 'HTML') {
3612                         val = '#fff';
3613                     }
3614                 }
3615             }
3616         } else {
3617             val = superclass.getAttribute.call(this, attr);
3618         }
3619
3620         return val;
3621     };
3622     proto.getAttribute = function(attr) {
3623         var el = this.getEl();
3624         if (this.patterns.color.test(attr)) {
3625             var val = fly(el).getStyle(attr);
3626
3627             if (this.patterns.transparent.test(val)) {
3628                 var parent = el.parentNode;
3629                 val = fly(parent).getStyle(attr);
3630
3631                 while (parent && this.patterns.transparent.test(val)) {
3632                     parent = parent.parentNode;
3633                     val = fly(parent).getStyle(attr);
3634                     if (parent.tagName.toUpperCase() == 'HTML') {
3635                         val = '#fff';
3636                     }
3637                 }
3638             }
3639         } else {
3640             val = superclass.getAttribute.call(this, attr);
3641         }
3642
3643         return val;
3644     };
3645
3646     proto.doMethod = function(attr, start, end) {
3647         var val;
3648
3649         if (this.patterns.color.test(attr)) {
3650             val = [];
3651             for (var i = 0, len = start.length; i < len; ++i) {
3652                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3653             }
3654
3655             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3656         }
3657         else {
3658             val = superclass.doMethod.call(this, attr, start, end);
3659         }
3660
3661         return val;
3662     };
3663
3664     proto.setRuntimeAttribute = function(attr) {
3665         superclass.setRuntimeAttribute.call(this, attr);
3666
3667         if (this.patterns.color.test(attr)) {
3668             var attributes = this.attributes;
3669             var start = this.parseColor(this.runtimeAttributes[attr].start);
3670             var end = this.parseColor(this.runtimeAttributes[attr].end);
3671
3672             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3673                 end = this.parseColor(attributes[attr].by);
3674
3675                 for (var i = 0, len = start.length; i < len; ++i) {
3676                     end[i] = start[i] + end[i];
3677                 }
3678             }
3679
3680             this.runtimeAttributes[attr].start = start;
3681             this.runtimeAttributes[attr].end = end;
3682         }
3683     };
3684 })();
3685
3686 /*
3687  * Portions of this file are based on pieces of Yahoo User Interface Library
3688  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3689  * YUI licensed under the BSD License:
3690  * http://developer.yahoo.net/yui/license.txt
3691  * <script type="text/javascript">
3692  *
3693  */
3694 Roo.lib.Easing = {
3695
3696
3697     easeNone: function (t, b, c, d) {
3698         return c * t / d + b;
3699     },
3700
3701
3702     easeIn: function (t, b, c, d) {
3703         return c * (t /= d) * t + b;
3704     },
3705
3706
3707     easeOut: function (t, b, c, d) {
3708         return -c * (t /= d) * (t - 2) + b;
3709     },
3710
3711
3712     easeBoth: function (t, b, c, d) {
3713         if ((t /= d / 2) < 1) {
3714             return c / 2 * t * t + b;
3715         }
3716
3717         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3718     },
3719
3720
3721     easeInStrong: function (t, b, c, d) {
3722         return c * (t /= d) * t * t * t + b;
3723     },
3724
3725
3726     easeOutStrong: function (t, b, c, d) {
3727         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3728     },
3729
3730
3731     easeBothStrong: function (t, b, c, d) {
3732         if ((t /= d / 2) < 1) {
3733             return c / 2 * t * t * t * t + b;
3734         }
3735
3736         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3737     },
3738
3739
3740
3741     elasticIn: function (t, b, c, d, a, p) {
3742         if (t == 0) {
3743             return b;
3744         }
3745         if ((t /= d) == 1) {
3746             return b + c;
3747         }
3748         if (!p) {
3749             p = d * .3;
3750         }
3751
3752         if (!a || a < Math.abs(c)) {
3753             a = c;
3754             var s = p / 4;
3755         }
3756         else {
3757             var s = p / (2 * Math.PI) * Math.asin(c / a);
3758         }
3759
3760         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3761     },
3762
3763
3764     elasticOut: function (t, b, c, d, a, p) {
3765         if (t == 0) {
3766             return b;
3767         }
3768         if ((t /= d) == 1) {
3769             return b + c;
3770         }
3771         if (!p) {
3772             p = d * .3;
3773         }
3774
3775         if (!a || a < Math.abs(c)) {
3776             a = c;
3777             var s = p / 4;
3778         }
3779         else {
3780             var s = p / (2 * Math.PI) * Math.asin(c / a);
3781         }
3782
3783         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3784     },
3785
3786
3787     elasticBoth: function (t, b, c, d, a, p) {
3788         if (t == 0) {
3789             return b;
3790         }
3791
3792         if ((t /= d / 2) == 2) {
3793             return b + c;
3794         }
3795
3796         if (!p) {
3797             p = d * (.3 * 1.5);
3798         }
3799
3800         if (!a || a < Math.abs(c)) {
3801             a = c;
3802             var s = p / 4;
3803         }
3804         else {
3805             var s = p / (2 * Math.PI) * Math.asin(c / a);
3806         }
3807
3808         if (t < 1) {
3809             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3810                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3811         }
3812         return a * Math.pow(2, -10 * (t -= 1)) *
3813                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3814     },
3815
3816
3817
3818     backIn: function (t, b, c, d, s) {
3819         if (typeof s == 'undefined') {
3820             s = 1.70158;
3821         }
3822         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3823     },
3824
3825
3826     backOut: function (t, b, c, d, s) {
3827         if (typeof s == 'undefined') {
3828             s = 1.70158;
3829         }
3830         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3831     },
3832
3833
3834     backBoth: function (t, b, c, d, s) {
3835         if (typeof s == 'undefined') {
3836             s = 1.70158;
3837         }
3838
3839         if ((t /= d / 2 ) < 1) {
3840             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3841         }
3842         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3843     },
3844
3845
3846     bounceIn: function (t, b, c, d) {
3847         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3848     },
3849
3850
3851     bounceOut: function (t, b, c, d) {
3852         if ((t /= d) < (1 / 2.75)) {
3853             return c * (7.5625 * t * t) + b;
3854         } else if (t < (2 / 2.75)) {
3855             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3856         } else if (t < (2.5 / 2.75)) {
3857             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3858         }
3859         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3860     },
3861
3862
3863     bounceBoth: function (t, b, c, d) {
3864         if (t < d / 2) {
3865             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3866         }
3867         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3868     }
3869 };/*
3870  * Portions of this file are based on pieces of Yahoo User Interface Library
3871  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3872  * YUI licensed under the BSD License:
3873  * http://developer.yahoo.net/yui/license.txt
3874  * <script type="text/javascript">
3875  *
3876  */
3877     (function() {
3878         Roo.lib.Motion = function(el, attributes, duration, method) {
3879             if (el) {
3880                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3881             }
3882         };
3883
3884         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3885
3886
3887         var Y = Roo.lib;
3888         var superclass = Y.Motion.superclass;
3889         var proto = Y.Motion.prototype;
3890
3891         proto.toString = function() {
3892             var el = this.getEl();
3893             var id = el.id || el.tagName;
3894             return ("Motion " + id);
3895         };
3896
3897         proto.patterns.points = /^points$/i;
3898
3899         proto.setAttribute = function(attr, val, unit) {
3900             if (this.patterns.points.test(attr)) {
3901                 unit = unit || 'px';
3902                 superclass.setAttribute.call(this, 'left', val[0], unit);
3903                 superclass.setAttribute.call(this, 'top', val[1], unit);
3904             } else {
3905                 superclass.setAttribute.call(this, attr, val, unit);
3906             }
3907         };
3908
3909         proto.getAttribute = function(attr) {
3910             if (this.patterns.points.test(attr)) {
3911                 var val = [
3912                         superclass.getAttribute.call(this, 'left'),
3913                         superclass.getAttribute.call(this, 'top')
3914                         ];
3915             } else {
3916                 val = superclass.getAttribute.call(this, attr);
3917             }
3918
3919             return val;
3920         };
3921
3922         proto.doMethod = function(attr, start, end) {
3923             var val = null;
3924
3925             if (this.patterns.points.test(attr)) {
3926                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3927                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3928             } else {
3929                 val = superclass.doMethod.call(this, attr, start, end);
3930             }
3931             return val;
3932         };
3933
3934         proto.setRuntimeAttribute = function(attr) {
3935             if (this.patterns.points.test(attr)) {
3936                 var el = this.getEl();
3937                 var attributes = this.attributes;
3938                 var start;
3939                 var control = attributes['points']['control'] || [];
3940                 var end;
3941                 var i, len;
3942
3943                 if (control.length > 0 && !(control[0] instanceof Array)) {
3944                     control = [control];
3945                 } else {
3946                     var tmp = [];
3947                     for (i = 0,len = control.length; i < len; ++i) {
3948                         tmp[i] = control[i];
3949                     }
3950                     control = tmp;
3951                 }
3952
3953                 Roo.fly(el).position();
3954
3955                 if (isset(attributes['points']['from'])) {
3956                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3957                 }
3958                 else {
3959                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3960                 }
3961
3962                 start = this.getAttribute('points');
3963
3964
3965                 if (isset(attributes['points']['to'])) {
3966                     end = translateValues.call(this, attributes['points']['to'], start);
3967
3968                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3969                     for (i = 0,len = control.length; i < len; ++i) {
3970                         control[i] = translateValues.call(this, control[i], start);
3971                     }
3972
3973
3974                 } else if (isset(attributes['points']['by'])) {
3975                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3976
3977                     for (i = 0,len = control.length; i < len; ++i) {
3978                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3979                     }
3980                 }
3981
3982                 this.runtimeAttributes[attr] = [start];
3983
3984                 if (control.length > 0) {
3985                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3986                 }
3987
3988                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3989             }
3990             else {
3991                 superclass.setRuntimeAttribute.call(this, attr);
3992             }
3993         };
3994
3995         var translateValues = function(val, start) {
3996             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3997             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3998
3999             return val;
4000         };
4001
4002         var isset = function(prop) {
4003             return (typeof prop !== 'undefined');
4004         };
4005     })();
4006 /*
4007  * Portions of this file are based on pieces of Yahoo User Interface Library
4008  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4009  * YUI licensed under the BSD License:
4010  * http://developer.yahoo.net/yui/license.txt
4011  * <script type="text/javascript">
4012  *
4013  */
4014     (function() {
4015         Roo.lib.Scroll = function(el, attributes, duration, method) {
4016             if (el) {
4017                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4018             }
4019         };
4020
4021         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4022
4023
4024         var Y = Roo.lib;
4025         var superclass = Y.Scroll.superclass;
4026         var proto = Y.Scroll.prototype;
4027
4028         proto.toString = function() {
4029             var el = this.getEl();
4030             var id = el.id || el.tagName;
4031             return ("Scroll " + id);
4032         };
4033
4034         proto.doMethod = function(attr, start, end) {
4035             var val = null;
4036
4037             if (attr == 'scroll') {
4038                 val = [
4039                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4040                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4041                         ];
4042
4043             } else {
4044                 val = superclass.doMethod.call(this, attr, start, end);
4045             }
4046             return val;
4047         };
4048
4049         proto.getAttribute = function(attr) {
4050             var val = null;
4051             var el = this.getEl();
4052
4053             if (attr == 'scroll') {
4054                 val = [ el.scrollLeft, el.scrollTop ];
4055             } else {
4056                 val = superclass.getAttribute.call(this, attr);
4057             }
4058
4059             return val;
4060         };
4061
4062         proto.setAttribute = function(attr, val, unit) {
4063             var el = this.getEl();
4064
4065             if (attr == 'scroll') {
4066                 el.scrollLeft = val[0];
4067                 el.scrollTop = val[1];
4068             } else {
4069                 superclass.setAttribute.call(this, attr, val, unit);
4070             }
4071         };
4072     })();
4073 /*
4074  * Based on:
4075  * Ext JS Library 1.1.1
4076  * Copyright(c) 2006-2007, Ext JS, LLC.
4077  *
4078  * Originally Released Under LGPL - original licence link has changed is not relivant.
4079  *
4080  * Fork - LGPL
4081  * <script type="text/javascript">
4082  */
4083
4084
4085 // nasty IE9 hack - what a pile of crap that is..
4086
4087  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4088     Range.prototype.createContextualFragment = function (html) {
4089         var doc = window.document;
4090         var container = doc.createElement("div");
4091         container.innerHTML = html;
4092         var frag = doc.createDocumentFragment(), n;
4093         while ((n = container.firstChild)) {
4094             frag.appendChild(n);
4095         }
4096         return frag;
4097     };
4098 }
4099
4100 /**
4101  * @class Roo.DomHelper
4102  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4103  * 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>.
4104  * @singleton
4105  */
4106 Roo.DomHelper = function(){
4107     var tempTableEl = null;
4108     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4109     var tableRe = /^table|tbody|tr|td$/i;
4110     var xmlns = {};
4111     // build as innerHTML where available
4112     /** @ignore */
4113     var createHtml = function(o){
4114         if(typeof o == 'string'){
4115             return o;
4116         }
4117         var b = "";
4118         if(!o.tag){
4119             o.tag = "div";
4120         }
4121         b += "<" + o.tag;
4122         for(var attr in o){
4123             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4124             if(attr == "style"){
4125                 var s = o["style"];
4126                 if(typeof s == "function"){
4127                     s = s.call();
4128                 }
4129                 if(typeof s == "string"){
4130                     b += ' style="' + s + '"';
4131                 }else if(typeof s == "object"){
4132                     b += ' style="';
4133                     for(var key in s){
4134                         if(typeof s[key] != "function"){
4135                             b += key + ":" + s[key] + ";";
4136                         }
4137                     }
4138                     b += '"';
4139                 }
4140             }else{
4141                 if(attr == "cls"){
4142                     b += ' class="' + o["cls"] + '"';
4143                 }else if(attr == "htmlFor"){
4144                     b += ' for="' + o["htmlFor"] + '"';
4145                 }else{
4146                     b += " " + attr + '="' + o[attr] + '"';
4147                 }
4148             }
4149         }
4150         if(emptyTags.test(o.tag)){
4151             b += "/>";
4152         }else{
4153             b += ">";
4154             var cn = o.children || o.cn;
4155             if(cn){
4156                 //http://bugs.kde.org/show_bug.cgi?id=71506
4157                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4158                     for(var i = 0, len = cn.length; i < len; i++) {
4159                         b += createHtml(cn[i], b);
4160                     }
4161                 }else{
4162                     b += createHtml(cn, b);
4163                 }
4164             }
4165             if(o.html){
4166                 b += o.html;
4167             }
4168             b += "</" + o.tag + ">";
4169         }
4170         return b;
4171     };
4172
4173     // build as dom
4174     /** @ignore */
4175     var createDom = function(o, parentNode){
4176          
4177         // defininition craeted..
4178         var ns = false;
4179         if (o.ns && o.ns != 'html') {
4180                
4181             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4182                 xmlns[o.ns] = o.xmlns;
4183                 ns = o.xmlns;
4184             }
4185             if (typeof(xmlns[o.ns]) == 'undefined') {
4186                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4187             }
4188             ns = xmlns[o.ns];
4189         }
4190         
4191         
4192         if (typeof(o) == 'string') {
4193             return parentNode.appendChild(document.createTextNode(o));
4194         }
4195         o.tag = o.tag || div;
4196         if (o.ns && Roo.isIE) {
4197             ns = false;
4198             o.tag = o.ns + ':' + o.tag;
4199             
4200         }
4201         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4202         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4203         for(var attr in o){
4204             
4205             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4206                     attr == "style" || typeof o[attr] == "function") continue;
4207                     
4208             if(attr=="cls" && Roo.isIE){
4209                 el.className = o["cls"];
4210             }else{
4211                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4212                 else el[attr] = o[attr];
4213             }
4214         }
4215         Roo.DomHelper.applyStyles(el, o.style);
4216         var cn = o.children || o.cn;
4217         if(cn){
4218             //http://bugs.kde.org/show_bug.cgi?id=71506
4219              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4220                 for(var i = 0, len = cn.length; i < len; i++) {
4221                     createDom(cn[i], el);
4222                 }
4223             }else{
4224                 createDom(cn, el);
4225             }
4226         }
4227         if(o.html){
4228             el.innerHTML = o.html;
4229         }
4230         if(parentNode){
4231            parentNode.appendChild(el);
4232         }
4233         return el;
4234     };
4235
4236     var ieTable = function(depth, s, h, e){
4237         tempTableEl.innerHTML = [s, h, e].join('');
4238         var i = -1, el = tempTableEl;
4239         while(++i < depth){
4240             el = el.firstChild;
4241         }
4242         return el;
4243     };
4244
4245     // kill repeat to save bytes
4246     var ts = '<table>',
4247         te = '</table>',
4248         tbs = ts+'<tbody>',
4249         tbe = '</tbody>'+te,
4250         trs = tbs + '<tr>',
4251         tre = '</tr>'+tbe;
4252
4253     /**
4254      * @ignore
4255      * Nasty code for IE's broken table implementation
4256      */
4257     var insertIntoTable = function(tag, where, el, html){
4258         if(!tempTableEl){
4259             tempTableEl = document.createElement('div');
4260         }
4261         var node;
4262         var before = null;
4263         if(tag == 'td'){
4264             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4265                 return;
4266             }
4267             if(where == 'beforebegin'){
4268                 before = el;
4269                 el = el.parentNode;
4270             } else{
4271                 before = el.nextSibling;
4272                 el = el.parentNode;
4273             }
4274             node = ieTable(4, trs, html, tre);
4275         }
4276         else if(tag == 'tr'){
4277             if(where == 'beforebegin'){
4278                 before = el;
4279                 el = el.parentNode;
4280                 node = ieTable(3, tbs, html, tbe);
4281             } else if(where == 'afterend'){
4282                 before = el.nextSibling;
4283                 el = el.parentNode;
4284                 node = ieTable(3, tbs, html, tbe);
4285             } else{ // INTO a TR
4286                 if(where == 'afterbegin'){
4287                     before = el.firstChild;
4288                 }
4289                 node = ieTable(4, trs, html, tre);
4290             }
4291         } else if(tag == 'tbody'){
4292             if(where == 'beforebegin'){
4293                 before = el;
4294                 el = el.parentNode;
4295                 node = ieTable(2, ts, html, te);
4296             } else if(where == 'afterend'){
4297                 before = el.nextSibling;
4298                 el = el.parentNode;
4299                 node = ieTable(2, ts, html, te);
4300             } else{
4301                 if(where == 'afterbegin'){
4302                     before = el.firstChild;
4303                 }
4304                 node = ieTable(3, tbs, html, tbe);
4305             }
4306         } else{ // TABLE
4307             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4308                 return;
4309             }
4310             if(where == 'afterbegin'){
4311                 before = el.firstChild;
4312             }
4313             node = ieTable(2, ts, html, te);
4314         }
4315         el.insertBefore(node, before);
4316         return node;
4317     };
4318
4319     return {
4320     /** True to force the use of DOM instead of html fragments @type Boolean */
4321     useDom : false,
4322
4323     /**
4324      * Returns the markup for the passed Element(s) config
4325      * @param {Object} o The Dom object spec (and children)
4326      * @return {String}
4327      */
4328     markup : function(o){
4329         return createHtml(o);
4330     },
4331
4332     /**
4333      * Applies a style specification to an element
4334      * @param {String/HTMLElement} el The element to apply styles to
4335      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4336      * a function which returns such a specification.
4337      */
4338     applyStyles : function(el, styles){
4339         if(styles){
4340            el = Roo.fly(el);
4341            if(typeof styles == "string"){
4342                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4343                var matches;
4344                while ((matches = re.exec(styles)) != null){
4345                    el.setStyle(matches[1], matches[2]);
4346                }
4347            }else if (typeof styles == "object"){
4348                for (var style in styles){
4349                   el.setStyle(style, styles[style]);
4350                }
4351            }else if (typeof styles == "function"){
4352                 Roo.DomHelper.applyStyles(el, styles.call());
4353            }
4354         }
4355     },
4356
4357     /**
4358      * Inserts an HTML fragment into the Dom
4359      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4360      * @param {HTMLElement} el The context element
4361      * @param {String} html The HTML fragmenet
4362      * @return {HTMLElement} The new node
4363      */
4364     insertHtml : function(where, el, html){
4365         where = where.toLowerCase();
4366         if(el.insertAdjacentHTML){
4367             if(tableRe.test(el.tagName)){
4368                 var rs;
4369                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4370                     return rs;
4371                 }
4372             }
4373             switch(where){
4374                 case "beforebegin":
4375                     el.insertAdjacentHTML('BeforeBegin', html);
4376                     return el.previousSibling;
4377                 case "afterbegin":
4378                     el.insertAdjacentHTML('AfterBegin', html);
4379                     return el.firstChild;
4380                 case "beforeend":
4381                     el.insertAdjacentHTML('BeforeEnd', html);
4382                     return el.lastChild;
4383                 case "afterend":
4384                     el.insertAdjacentHTML('AfterEnd', html);
4385                     return el.nextSibling;
4386             }
4387             throw 'Illegal insertion point -> "' + where + '"';
4388         }
4389         var range = el.ownerDocument.createRange();
4390         var frag;
4391         switch(where){
4392              case "beforebegin":
4393                 range.setStartBefore(el);
4394                 frag = range.createContextualFragment(html);
4395                 el.parentNode.insertBefore(frag, el);
4396                 return el.previousSibling;
4397              case "afterbegin":
4398                 if(el.firstChild){
4399                     range.setStartBefore(el.firstChild);
4400                     frag = range.createContextualFragment(html);
4401                     el.insertBefore(frag, el.firstChild);
4402                     return el.firstChild;
4403                 }else{
4404                     el.innerHTML = html;
4405                     return el.firstChild;
4406                 }
4407             case "beforeend":
4408                 if(el.lastChild){
4409                     range.setStartAfter(el.lastChild);
4410                     frag = range.createContextualFragment(html);
4411                     el.appendChild(frag);
4412                     return el.lastChild;
4413                 }else{
4414                     el.innerHTML = html;
4415                     return el.lastChild;
4416                 }
4417             case "afterend":
4418                 range.setStartAfter(el);
4419                 frag = range.createContextualFragment(html);
4420                 el.parentNode.insertBefore(frag, el.nextSibling);
4421                 return el.nextSibling;
4422             }
4423             throw 'Illegal insertion point -> "' + where + '"';
4424     },
4425
4426     /**
4427      * Creates new Dom element(s) and inserts them before el
4428      * @param {String/HTMLElement/Element} el The context element
4429      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4430      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4431      * @return {HTMLElement/Roo.Element} The new node
4432      */
4433     insertBefore : function(el, o, returnElement){
4434         return this.doInsert(el, o, returnElement, "beforeBegin");
4435     },
4436
4437     /**
4438      * Creates new Dom element(s) and inserts them after el
4439      * @param {String/HTMLElement/Element} el The context element
4440      * @param {Object} o The Dom object spec (and children)
4441      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4442      * @return {HTMLElement/Roo.Element} The new node
4443      */
4444     insertAfter : function(el, o, returnElement){
4445         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4446     },
4447
4448     /**
4449      * Creates new Dom element(s) and inserts them as the first child of el
4450      * @param {String/HTMLElement/Element} el The context element
4451      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4452      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4453      * @return {HTMLElement/Roo.Element} The new node
4454      */
4455     insertFirst : function(el, o, returnElement){
4456         return this.doInsert(el, o, returnElement, "afterBegin");
4457     },
4458
4459     // private
4460     doInsert : function(el, o, returnElement, pos, sibling){
4461         el = Roo.getDom(el);
4462         var newNode;
4463         if(this.useDom || o.ns){
4464             newNode = createDom(o, null);
4465             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4466         }else{
4467             var html = createHtml(o);
4468             newNode = this.insertHtml(pos, el, html);
4469         }
4470         return returnElement ? Roo.get(newNode, true) : newNode;
4471     },
4472
4473     /**
4474      * Creates new Dom element(s) and appends them to el
4475      * @param {String/HTMLElement/Element} el The context element
4476      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4477      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4478      * @return {HTMLElement/Roo.Element} The new node
4479      */
4480     append : function(el, o, returnElement){
4481         el = Roo.getDom(el);
4482         var newNode;
4483         if(this.useDom || o.ns){
4484             newNode = createDom(o, null);
4485             el.appendChild(newNode);
4486         }else{
4487             var html = createHtml(o);
4488             newNode = this.insertHtml("beforeEnd", el, html);
4489         }
4490         return returnElement ? Roo.get(newNode, true) : newNode;
4491     },
4492
4493     /**
4494      * Creates new Dom element(s) and overwrites the contents of el with them
4495      * @param {String/HTMLElement/Element} el The context element
4496      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4497      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4498      * @return {HTMLElement/Roo.Element} The new node
4499      */
4500     overwrite : function(el, o, returnElement){
4501         el = Roo.getDom(el);
4502         if (o.ns) {
4503           
4504             while (el.childNodes.length) {
4505                 el.removeChild(el.firstChild);
4506             }
4507             createDom(o, el);
4508         } else {
4509             el.innerHTML = createHtml(o);   
4510         }
4511         
4512         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4513     },
4514
4515     /**
4516      * Creates a new Roo.DomHelper.Template from the Dom object spec
4517      * @param {Object} o The Dom object spec (and children)
4518      * @return {Roo.DomHelper.Template} The new template
4519      */
4520     createTemplate : function(o){
4521         var html = createHtml(o);
4522         return new Roo.Template(html);
4523     }
4524     };
4525 }();
4526 /*
4527  * Based on:
4528  * Ext JS Library 1.1.1
4529  * Copyright(c) 2006-2007, Ext JS, LLC.
4530  *
4531  * Originally Released Under LGPL - original licence link has changed is not relivant.
4532  *
4533  * Fork - LGPL
4534  * <script type="text/javascript">
4535  */
4536  
4537 /**
4538 * @class Roo.Template
4539 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4540 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4541 * Usage:
4542 <pre><code>
4543 var t = new Roo.Template({
4544     html :  '&lt;div name="{id}"&gt;' + 
4545         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4546         '&lt;/div&gt;',
4547     myformat: function (value, allValues) {
4548         return 'XX' + value;
4549     }
4550 });
4551 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4552 </code></pre>
4553 * For more information see this blog post with examples:
4554 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4555      - Create Elements using DOM, HTML fragments and Templates</a>. 
4556 * @constructor
4557 * @param {Object} cfg - Configuration object.
4558 */
4559 Roo.Template = function(cfg){
4560     // BC!
4561     if(cfg instanceof Array){
4562         cfg = cfg.join("");
4563     }else if(arguments.length > 1){
4564         cfg = Array.prototype.join.call(arguments, "");
4565     }
4566     
4567     
4568     if (typeof(cfg) == 'object') {
4569         Roo.apply(this,cfg)
4570     } else {
4571         // bc
4572         this.html = cfg;
4573     }
4574     if (this.url) {
4575         this.load();
4576     }
4577     
4578 };
4579 Roo.Template.prototype = {
4580     
4581     /**
4582      * @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..
4583      *                    it should be fixed so that template is observable...
4584      */
4585     url : false,
4586     /**
4587      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4588      */
4589     html : '',
4590     /**
4591      * Returns an HTML fragment of this template with the specified values applied.
4592      * @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'})
4593      * @return {String} The HTML fragment
4594      */
4595     applyTemplate : function(values){
4596         try {
4597            
4598             if(this.compiled){
4599                 return this.compiled(values);
4600             }
4601             var useF = this.disableFormats !== true;
4602             var fm = Roo.util.Format, tpl = this;
4603             var fn = function(m, name, format, args){
4604                 if(format && useF){
4605                     if(format.substr(0, 5) == "this."){
4606                         return tpl.call(format.substr(5), values[name], values);
4607                     }else{
4608                         if(args){
4609                             // quoted values are required for strings in compiled templates, 
4610                             // but for non compiled we need to strip them
4611                             // quoted reversed for jsmin
4612                             var re = /^\s*['"](.*)["']\s*$/;
4613                             args = args.split(',');
4614                             for(var i = 0, len = args.length; i < len; i++){
4615                                 args[i] = args[i].replace(re, "$1");
4616                             }
4617                             args = [values[name]].concat(args);
4618                         }else{
4619                             args = [values[name]];
4620                         }
4621                         return fm[format].apply(fm, args);
4622                     }
4623                 }else{
4624                     return values[name] !== undefined ? values[name] : "";
4625                 }
4626             };
4627             return this.html.replace(this.re, fn);
4628         } catch (e) {
4629             Roo.log(e);
4630             throw e;
4631         }
4632          
4633     },
4634     
4635     loading : false,
4636       
4637     load : function ()
4638     {
4639          
4640         if (this.loading) {
4641             return;
4642         }
4643         var _t = this;
4644         
4645         this.loading = true;
4646         this.compiled = false;
4647         
4648         var cx = new Roo.data.Connection();
4649         cx.request({
4650             url : this.url,
4651             method : 'GET',
4652             success : function (response) {
4653                 _t.loading = false;
4654                 _t.html = response.responseText;
4655                 _t.url = false;
4656                 _t.compile();
4657              },
4658             failure : function(response) {
4659                 Roo.log("Template failed to load from " + _t.url);
4660                 _t.loading = false;
4661             }
4662         });
4663     },
4664
4665     /**
4666      * Sets the HTML used as the template and optionally compiles it.
4667      * @param {String} html
4668      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4669      * @return {Roo.Template} this
4670      */
4671     set : function(html, compile){
4672         this.html = html;
4673         this.compiled = null;
4674         if(compile){
4675             this.compile();
4676         }
4677         return this;
4678     },
4679     
4680     /**
4681      * True to disable format functions (defaults to false)
4682      * @type Boolean
4683      */
4684     disableFormats : false,
4685     
4686     /**
4687     * The regular expression used to match template variables 
4688     * @type RegExp
4689     * @property 
4690     */
4691     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4692     
4693     /**
4694      * Compiles the template into an internal function, eliminating the RegEx overhead.
4695      * @return {Roo.Template} this
4696      */
4697     compile : function(){
4698         var fm = Roo.util.Format;
4699         var useF = this.disableFormats !== true;
4700         var sep = Roo.isGecko ? "+" : ",";
4701         var fn = function(m, name, format, args){
4702             if(format && useF){
4703                 args = args ? ',' + args : "";
4704                 if(format.substr(0, 5) != "this."){
4705                     format = "fm." + format + '(';
4706                 }else{
4707                     format = 'this.call("'+ format.substr(5) + '", ';
4708                     args = ", values";
4709                 }
4710             }else{
4711                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4712             }
4713             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4714         };
4715         var body;
4716         // branched to use + in gecko and [].join() in others
4717         if(Roo.isGecko){
4718             body = "this.compiled = function(values){ return '" +
4719                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4720                     "';};";
4721         }else{
4722             body = ["this.compiled = function(values){ return ['"];
4723             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4724             body.push("'].join('');};");
4725             body = body.join('');
4726         }
4727         /**
4728          * eval:var:values
4729          * eval:var:fm
4730          */
4731         eval(body);
4732         return this;
4733     },
4734     
4735     // private function used to call members
4736     call : function(fnName, value, allValues){
4737         return this[fnName](value, allValues);
4738     },
4739     
4740     /**
4741      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4742      * @param {String/HTMLElement/Roo.Element} el The context element
4743      * @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'})
4744      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4745      * @return {HTMLElement/Roo.Element} The new node or Element
4746      */
4747     insertFirst: function(el, values, returnElement){
4748         return this.doInsert('afterBegin', el, values, returnElement);
4749     },
4750
4751     /**
4752      * Applies the supplied values to the template and inserts the new node(s) before el.
4753      * @param {String/HTMLElement/Roo.Element} el The context element
4754      * @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'})
4755      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4756      * @return {HTMLElement/Roo.Element} The new node or Element
4757      */
4758     insertBefore: function(el, values, returnElement){
4759         return this.doInsert('beforeBegin', el, values, returnElement);
4760     },
4761
4762     /**
4763      * Applies the supplied values to the template and inserts the new node(s) after el.
4764      * @param {String/HTMLElement/Roo.Element} el The context element
4765      * @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'})
4766      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4767      * @return {HTMLElement/Roo.Element} The new node or Element
4768      */
4769     insertAfter : function(el, values, returnElement){
4770         return this.doInsert('afterEnd', el, values, returnElement);
4771     },
4772     
4773     /**
4774      * Applies the supplied values to the template and appends the new node(s) to el.
4775      * @param {String/HTMLElement/Roo.Element} el The context element
4776      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4777      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778      * @return {HTMLElement/Roo.Element} The new node or Element
4779      */
4780     append : function(el, values, returnElement){
4781         return this.doInsert('beforeEnd', el, values, returnElement);
4782     },
4783
4784     doInsert : function(where, el, values, returnEl){
4785         el = Roo.getDom(el);
4786         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4787         return returnEl ? Roo.get(newNode, true) : newNode;
4788     },
4789
4790     /**
4791      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4792      * @param {String/HTMLElement/Roo.Element} el The context element
4793      * @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'})
4794      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4795      * @return {HTMLElement/Roo.Element} The new node or Element
4796      */
4797     overwrite : function(el, values, returnElement){
4798         el = Roo.getDom(el);
4799         el.innerHTML = this.applyTemplate(values);
4800         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4801     }
4802 };
4803 /**
4804  * Alias for {@link #applyTemplate}
4805  * @method
4806  */
4807 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4808
4809 // backwards compat
4810 Roo.DomHelper.Template = Roo.Template;
4811
4812 /**
4813  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4814  * @param {String/HTMLElement} el A DOM element or its id
4815  * @returns {Roo.Template} The created template
4816  * @static
4817  */
4818 Roo.Template.from = function(el){
4819     el = Roo.getDom(el);
4820     return new Roo.Template(el.value || el.innerHTML);
4821 };/*
4822  * Based on:
4823  * Ext JS Library 1.1.1
4824  * Copyright(c) 2006-2007, Ext JS, LLC.
4825  *
4826  * Originally Released Under LGPL - original licence link has changed is not relivant.
4827  *
4828  * Fork - LGPL
4829  * <script type="text/javascript">
4830  */
4831  
4832
4833 /*
4834  * This is code is also distributed under MIT license for use
4835  * with jQuery and prototype JavaScript libraries.
4836  */
4837 /**
4838  * @class Roo.DomQuery
4839 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).
4840 <p>
4841 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>
4842
4843 <p>
4844 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.
4845 </p>
4846 <h4>Element Selectors:</h4>
4847 <ul class="list">
4848     <li> <b>*</b> any element</li>
4849     <li> <b>E</b> an element with the tag E</li>
4850     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4851     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4852     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4853     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4854 </ul>
4855 <h4>Attribute Selectors:</h4>
4856 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4857 <ul class="list">
4858     <li> <b>E[foo]</b> has an attribute "foo"</li>
4859     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4860     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4861     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4862     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4863     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4864     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4865 </ul>
4866 <h4>Pseudo Classes:</h4>
4867 <ul class="list">
4868     <li> <b>E:first-child</b> E is the first child of its parent</li>
4869     <li> <b>E:last-child</b> E is the last child of its parent</li>
4870     <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>
4871     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4872     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4873     <li> <b>E:only-child</b> E is the only child of its parent</li>
4874     <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>
4875     <li> <b>E:first</b> the first E in the resultset</li>
4876     <li> <b>E:last</b> the last E in the resultset</li>
4877     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4878     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4879     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4880     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4881     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4882     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4883     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4884     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4885     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4886 </ul>
4887 <h4>CSS Value Selectors:</h4>
4888 <ul class="list">
4889     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4890     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4891     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4892     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4893     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4894     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4895 </ul>
4896  * @singleton
4897  */
4898 Roo.DomQuery = function(){
4899     var cache = {}, simpleCache = {}, valueCache = {};
4900     var nonSpace = /\S/;
4901     var trimRe = /^\s+|\s+$/g;
4902     var tplRe = /\{(\d+)\}/g;
4903     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4904     var tagTokenRe = /^(#)?([\w-\*]+)/;
4905     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4906
4907     function child(p, index){
4908         var i = 0;
4909         var n = p.firstChild;
4910         while(n){
4911             if(n.nodeType == 1){
4912                if(++i == index){
4913                    return n;
4914                }
4915             }
4916             n = n.nextSibling;
4917         }
4918         return null;
4919     };
4920
4921     function next(n){
4922         while((n = n.nextSibling) && n.nodeType != 1);
4923         return n;
4924     };
4925
4926     function prev(n){
4927         while((n = n.previousSibling) && n.nodeType != 1);
4928         return n;
4929     };
4930
4931     function children(d){
4932         var n = d.firstChild, ni = -1;
4933             while(n){
4934                 var nx = n.nextSibling;
4935                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4936                     d.removeChild(n);
4937                 }else{
4938                     n.nodeIndex = ++ni;
4939                 }
4940                 n = nx;
4941             }
4942             return this;
4943         };
4944
4945     function byClassName(c, a, v){
4946         if(!v){
4947             return c;
4948         }
4949         var r = [], ri = -1, cn;
4950         for(var i = 0, ci; ci = c[i]; i++){
4951             if((' '+ci.className+' ').indexOf(v) != -1){
4952                 r[++ri] = ci;
4953             }
4954         }
4955         return r;
4956     };
4957
4958     function attrValue(n, attr){
4959         if(!n.tagName && typeof n.length != "undefined"){
4960             n = n[0];
4961         }
4962         if(!n){
4963             return null;
4964         }
4965         if(attr == "for"){
4966             return n.htmlFor;
4967         }
4968         if(attr == "class" || attr == "className"){
4969             return n.className;
4970         }
4971         return n.getAttribute(attr) || n[attr];
4972
4973     };
4974
4975     function getNodes(ns, mode, tagName){
4976         var result = [], ri = -1, cs;
4977         if(!ns){
4978             return result;
4979         }
4980         tagName = tagName || "*";
4981         if(typeof ns.getElementsByTagName != "undefined"){
4982             ns = [ns];
4983         }
4984         if(!mode){
4985             for(var i = 0, ni; ni = ns[i]; i++){
4986                 cs = ni.getElementsByTagName(tagName);
4987                 for(var j = 0, ci; ci = cs[j]; j++){
4988                     result[++ri] = ci;
4989                 }
4990             }
4991         }else if(mode == "/" || mode == ">"){
4992             var utag = tagName.toUpperCase();
4993             for(var i = 0, ni, cn; ni = ns[i]; i++){
4994                 cn = ni.children || ni.childNodes;
4995                 for(var j = 0, cj; cj = cn[j]; j++){
4996                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4997                         result[++ri] = cj;
4998                     }
4999                 }
5000             }
5001         }else if(mode == "+"){
5002             var utag = tagName.toUpperCase();
5003             for(var i = 0, n; n = ns[i]; i++){
5004                 while((n = n.nextSibling) && n.nodeType != 1);
5005                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5006                     result[++ri] = n;
5007                 }
5008             }
5009         }else if(mode == "~"){
5010             for(var i = 0, n; n = ns[i]; i++){
5011                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5012                 if(n){
5013                     result[++ri] = n;
5014                 }
5015             }
5016         }
5017         return result;
5018     };
5019
5020     function concat(a, b){
5021         if(b.slice){
5022             return a.concat(b);
5023         }
5024         for(var i = 0, l = b.length; i < l; i++){
5025             a[a.length] = b[i];
5026         }
5027         return a;
5028     }
5029
5030     function byTag(cs, tagName){
5031         if(cs.tagName || cs == document){
5032             cs = [cs];
5033         }
5034         if(!tagName){
5035             return cs;
5036         }
5037         var r = [], ri = -1;
5038         tagName = tagName.toLowerCase();
5039         for(var i = 0, ci; ci = cs[i]; i++){
5040             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5041                 r[++ri] = ci;
5042             }
5043         }
5044         return r;
5045     };
5046
5047     function byId(cs, attr, id){
5048         if(cs.tagName || cs == document){
5049             cs = [cs];
5050         }
5051         if(!id){
5052             return cs;
5053         }
5054         var r = [], ri = -1;
5055         for(var i = 0,ci; ci = cs[i]; i++){
5056             if(ci && ci.id == id){
5057                 r[++ri] = ci;
5058                 return r;
5059             }
5060         }
5061         return r;
5062     };
5063
5064     function byAttribute(cs, attr, value, op, custom){
5065         var r = [], ri = -1, st = custom=="{";
5066         var f = Roo.DomQuery.operators[op];
5067         for(var i = 0, ci; ci = cs[i]; i++){
5068             var a;
5069             if(st){
5070                 a = Roo.DomQuery.getStyle(ci, attr);
5071             }
5072             else if(attr == "class" || attr == "className"){
5073                 a = ci.className;
5074             }else if(attr == "for"){
5075                 a = ci.htmlFor;
5076             }else if(attr == "href"){
5077                 a = ci.getAttribute("href", 2);
5078             }else{
5079                 a = ci.getAttribute(attr);
5080             }
5081             if((f && f(a, value)) || (!f && a)){
5082                 r[++ri] = ci;
5083             }
5084         }
5085         return r;
5086     };
5087
5088     function byPseudo(cs, name, value){
5089         return Roo.DomQuery.pseudos[name](cs, value);
5090     };
5091
5092     // This is for IE MSXML which does not support expandos.
5093     // IE runs the same speed using setAttribute, however FF slows way down
5094     // and Safari completely fails so they need to continue to use expandos.
5095     var isIE = window.ActiveXObject ? true : false;
5096
5097     // this eval is stop the compressor from
5098     // renaming the variable to something shorter
5099     
5100     /** eval:var:batch */
5101     var batch = 30803; 
5102
5103     var key = 30803;
5104
5105     function nodupIEXml(cs){
5106         var d = ++key;
5107         cs[0].setAttribute("_nodup", d);
5108         var r = [cs[0]];
5109         for(var i = 1, len = cs.length; i < len; i++){
5110             var c = cs[i];
5111             if(!c.getAttribute("_nodup") != d){
5112                 c.setAttribute("_nodup", d);
5113                 r[r.length] = c;
5114             }
5115         }
5116         for(var i = 0, len = cs.length; i < len; i++){
5117             cs[i].removeAttribute("_nodup");
5118         }
5119         return r;
5120     }
5121
5122     function nodup(cs){
5123         if(!cs){
5124             return [];
5125         }
5126         var len = cs.length, c, i, r = cs, cj, ri = -1;
5127         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5128             return cs;
5129         }
5130         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5131             return nodupIEXml(cs);
5132         }
5133         var d = ++key;
5134         cs[0]._nodup = d;
5135         for(i = 1; c = cs[i]; i++){
5136             if(c._nodup != d){
5137                 c._nodup = d;
5138             }else{
5139                 r = [];
5140                 for(var j = 0; j < i; j++){
5141                     r[++ri] = cs[j];
5142                 }
5143                 for(j = i+1; cj = cs[j]; j++){
5144                     if(cj._nodup != d){
5145                         cj._nodup = d;
5146                         r[++ri] = cj;
5147                     }
5148                 }
5149                 return r;
5150             }
5151         }
5152         return r;
5153     }
5154
5155     function quickDiffIEXml(c1, c2){
5156         var d = ++key;
5157         for(var i = 0, len = c1.length; i < len; i++){
5158             c1[i].setAttribute("_qdiff", d);
5159         }
5160         var r = [];
5161         for(var i = 0, len = c2.length; i < len; i++){
5162             if(c2[i].getAttribute("_qdiff") != d){
5163                 r[r.length] = c2[i];
5164             }
5165         }
5166         for(var i = 0, len = c1.length; i < len; i++){
5167            c1[i].removeAttribute("_qdiff");
5168         }
5169         return r;
5170     }
5171
5172     function quickDiff(c1, c2){
5173         var len1 = c1.length;
5174         if(!len1){
5175             return c2;
5176         }
5177         if(isIE && c1[0].selectSingleNode){
5178             return quickDiffIEXml(c1, c2);
5179         }
5180         var d = ++key;
5181         for(var i = 0; i < len1; i++){
5182             c1[i]._qdiff = d;
5183         }
5184         var r = [];
5185         for(var i = 0, len = c2.length; i < len; i++){
5186             if(c2[i]._qdiff != d){
5187                 r[r.length] = c2[i];
5188             }
5189         }
5190         return r;
5191     }
5192
5193     function quickId(ns, mode, root, id){
5194         if(ns == root){
5195            var d = root.ownerDocument || root;
5196            return d.getElementById(id);
5197         }
5198         ns = getNodes(ns, mode, "*");
5199         return byId(ns, null, id);
5200     }
5201
5202     return {
5203         getStyle : function(el, name){
5204             return Roo.fly(el).getStyle(name);
5205         },
5206         /**
5207          * Compiles a selector/xpath query into a reusable function. The returned function
5208          * takes one parameter "root" (optional), which is the context node from where the query should start.
5209          * @param {String} selector The selector/xpath query
5210          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5211          * @return {Function}
5212          */
5213         compile : function(path, type){
5214             type = type || "select";
5215             
5216             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5217             var q = path, mode, lq;
5218             var tk = Roo.DomQuery.matchers;
5219             var tklen = tk.length;
5220             var mm;
5221
5222             // accept leading mode switch
5223             var lmode = q.match(modeRe);
5224             if(lmode && lmode[1]){
5225                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5226                 q = q.replace(lmode[1], "");
5227             }
5228             // strip leading slashes
5229             while(path.substr(0, 1)=="/"){
5230                 path = path.substr(1);
5231             }
5232
5233             while(q && lq != q){
5234                 lq = q;
5235                 var tm = q.match(tagTokenRe);
5236                 if(type == "select"){
5237                     if(tm){
5238                         if(tm[1] == "#"){
5239                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5240                         }else{
5241                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5242                         }
5243                         q = q.replace(tm[0], "");
5244                     }else if(q.substr(0, 1) != '@'){
5245                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5246                     }
5247                 }else{
5248                     if(tm){
5249                         if(tm[1] == "#"){
5250                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5251                         }else{
5252                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5253                         }
5254                         q = q.replace(tm[0], "");
5255                     }
5256                 }
5257                 while(!(mm = q.match(modeRe))){
5258                     var matched = false;
5259                     for(var j = 0; j < tklen; j++){
5260                         var t = tk[j];
5261                         var m = q.match(t.re);
5262                         if(m){
5263                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5264                                                     return m[i];
5265                                                 });
5266                             q = q.replace(m[0], "");
5267                             matched = true;
5268                             break;
5269                         }
5270                     }
5271                     // prevent infinite loop on bad selector
5272                     if(!matched){
5273                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5274                     }
5275                 }
5276                 if(mm[1]){
5277                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5278                     q = q.replace(mm[1], "");
5279                 }
5280             }
5281             fn[fn.length] = "return nodup(n);\n}";
5282             
5283              /** 
5284               * list of variables that need from compression as they are used by eval.
5285              *  eval:var:batch 
5286              *  eval:var:nodup
5287              *  eval:var:byTag
5288              *  eval:var:ById
5289              *  eval:var:getNodes
5290              *  eval:var:quickId
5291              *  eval:var:mode
5292              *  eval:var:root
5293              *  eval:var:n
5294              *  eval:var:byClassName
5295              *  eval:var:byPseudo
5296              *  eval:var:byAttribute
5297              *  eval:var:attrValue
5298              * 
5299              **/ 
5300             eval(fn.join(""));
5301             return f;
5302         },
5303
5304         /**
5305          * Selects a group of elements.
5306          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5307          * @param {Node} root (optional) The start of the query (defaults to document).
5308          * @return {Array}
5309          */
5310         select : function(path, root, type){
5311             if(!root || root == document){
5312                 root = document;
5313             }
5314             if(typeof root == "string"){
5315                 root = document.getElementById(root);
5316             }
5317             var paths = path.split(",");
5318             var results = [];
5319             for(var i = 0, len = paths.length; i < len; i++){
5320                 var p = paths[i].replace(trimRe, "");
5321                 if(!cache[p]){
5322                     cache[p] = Roo.DomQuery.compile(p);
5323                     if(!cache[p]){
5324                         throw p + " is not a valid selector";
5325                     }
5326                 }
5327                 var result = cache[p](root);
5328                 if(result && result != document){
5329                     results = results.concat(result);
5330                 }
5331             }
5332             if(paths.length > 1){
5333                 return nodup(results);
5334             }
5335             return results;
5336         },
5337
5338         /**
5339          * Selects a single element.
5340          * @param {String} selector The selector/xpath query
5341          * @param {Node} root (optional) The start of the query (defaults to document).
5342          * @return {Element}
5343          */
5344         selectNode : function(path, root){
5345             return Roo.DomQuery.select(path, root)[0];
5346         },
5347
5348         /**
5349          * Selects the value of a node, optionally replacing null with the defaultValue.
5350          * @param {String} selector The selector/xpath query
5351          * @param {Node} root (optional) The start of the query (defaults to document).
5352          * @param {String} defaultValue
5353          */
5354         selectValue : function(path, root, defaultValue){
5355             path = path.replace(trimRe, "");
5356             if(!valueCache[path]){
5357                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5358             }
5359             var n = valueCache[path](root);
5360             n = n[0] ? n[0] : n;
5361             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5362             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5363         },
5364
5365         /**
5366          * Selects the value of a node, parsing integers and floats.
5367          * @param {String} selector The selector/xpath query
5368          * @param {Node} root (optional) The start of the query (defaults to document).
5369          * @param {Number} defaultValue
5370          * @return {Number}
5371          */
5372         selectNumber : function(path, root, defaultValue){
5373             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5374             return parseFloat(v);
5375         },
5376
5377         /**
5378          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5379          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5380          * @param {String} selector The simple selector to test
5381          * @return {Boolean}
5382          */
5383         is : function(el, ss){
5384             if(typeof el == "string"){
5385                 el = document.getElementById(el);
5386             }
5387             var isArray = (el instanceof Array);
5388             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5389             return isArray ? (result.length == el.length) : (result.length > 0);
5390         },
5391
5392         /**
5393          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5394          * @param {Array} el An array of elements to filter
5395          * @param {String} selector The simple selector to test
5396          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5397          * the selector instead of the ones that match
5398          * @return {Array}
5399          */
5400         filter : function(els, ss, nonMatches){
5401             ss = ss.replace(trimRe, "");
5402             if(!simpleCache[ss]){
5403                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5404             }
5405             var result = simpleCache[ss](els);
5406             return nonMatches ? quickDiff(result, els) : result;
5407         },
5408
5409         /**
5410          * Collection of matching regular expressions and code snippets.
5411          */
5412         matchers : [{
5413                 re: /^\.([\w-]+)/,
5414                 select: 'n = byClassName(n, null, " {1} ");'
5415             }, {
5416                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5417                 select: 'n = byPseudo(n, "{1}", "{2}");'
5418             },{
5419                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5420                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5421             }, {
5422                 re: /^#([\w-]+)/,
5423                 select: 'n = byId(n, null, "{1}");'
5424             },{
5425                 re: /^@([\w-]+)/,
5426                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5427             }
5428         ],
5429
5430         /**
5431          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5432          * 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;.
5433          */
5434         operators : {
5435             "=" : function(a, v){
5436                 return a == v;
5437             },
5438             "!=" : function(a, v){
5439                 return a != v;
5440             },
5441             "^=" : function(a, v){
5442                 return a && a.substr(0, v.length) == v;
5443             },
5444             "$=" : function(a, v){
5445                 return a && a.substr(a.length-v.length) == v;
5446             },
5447             "*=" : function(a, v){
5448                 return a && a.indexOf(v) !== -1;
5449             },
5450             "%=" : function(a, v){
5451                 return (a % v) == 0;
5452             },
5453             "|=" : function(a, v){
5454                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5455             },
5456             "~=" : function(a, v){
5457                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5458             }
5459         },
5460
5461         /**
5462          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5463          * and the argument (if any) supplied in the selector.
5464          */
5465         pseudos : {
5466             "first-child" : function(c){
5467                 var r = [], ri = -1, n;
5468                 for(var i = 0, ci; ci = n = c[i]; i++){
5469                     while((n = n.previousSibling) && n.nodeType != 1);
5470                     if(!n){
5471                         r[++ri] = ci;
5472                     }
5473                 }
5474                 return r;
5475             },
5476
5477             "last-child" : function(c){
5478                 var r = [], ri = -1, n;
5479                 for(var i = 0, ci; ci = n = c[i]; i++){
5480                     while((n = n.nextSibling) && n.nodeType != 1);
5481                     if(!n){
5482                         r[++ri] = ci;
5483                     }
5484                 }
5485                 return r;
5486             },
5487
5488             "nth-child" : function(c, a) {
5489                 var r = [], ri = -1;
5490                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5491                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5492                 for(var i = 0, n; n = c[i]; i++){
5493                     var pn = n.parentNode;
5494                     if (batch != pn._batch) {
5495                         var j = 0;
5496                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5497                             if(cn.nodeType == 1){
5498                                cn.nodeIndex = ++j;
5499                             }
5500                         }
5501                         pn._batch = batch;
5502                     }
5503                     if (f == 1) {
5504                         if (l == 0 || n.nodeIndex == l){
5505                             r[++ri] = n;
5506                         }
5507                     } else if ((n.nodeIndex + l) % f == 0){
5508                         r[++ri] = n;
5509                     }
5510                 }
5511
5512                 return r;
5513             },
5514
5515             "only-child" : function(c){
5516                 var r = [], ri = -1;;
5517                 for(var i = 0, ci; ci = c[i]; i++){
5518                     if(!prev(ci) && !next(ci)){
5519                         r[++ri] = ci;
5520                     }
5521                 }
5522                 return r;
5523             },
5524
5525             "empty" : function(c){
5526                 var r = [], ri = -1;
5527                 for(var i = 0, ci; ci = c[i]; i++){
5528                     var cns = ci.childNodes, j = 0, cn, empty = true;
5529                     while(cn = cns[j]){
5530                         ++j;
5531                         if(cn.nodeType == 1 || cn.nodeType == 3){
5532                             empty = false;
5533                             break;
5534                         }
5535                     }
5536                     if(empty){
5537                         r[++ri] = ci;
5538                     }
5539                 }
5540                 return r;
5541             },
5542
5543             "contains" : function(c, v){
5544                 var r = [], ri = -1;
5545                 for(var i = 0, ci; ci = c[i]; i++){
5546                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5547                         r[++ri] = ci;
5548                     }
5549                 }
5550                 return r;
5551             },
5552
5553             "nodeValue" : function(c, v){
5554                 var r = [], ri = -1;
5555                 for(var i = 0, ci; ci = c[i]; i++){
5556                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5557                         r[++ri] = ci;
5558                     }
5559                 }
5560                 return r;
5561             },
5562
5563             "checked" : function(c){
5564                 var r = [], ri = -1;
5565                 for(var i = 0, ci; ci = c[i]; i++){
5566                     if(ci.checked == true){
5567                         r[++ri] = ci;
5568                     }
5569                 }
5570                 return r;
5571             },
5572
5573             "not" : function(c, ss){
5574                 return Roo.DomQuery.filter(c, ss, true);
5575             },
5576
5577             "odd" : function(c){
5578                 return this["nth-child"](c, "odd");
5579             },
5580
5581             "even" : function(c){
5582                 return this["nth-child"](c, "even");
5583             },
5584
5585             "nth" : function(c, a){
5586                 return c[a-1] || [];
5587             },
5588
5589             "first" : function(c){
5590                 return c[0] || [];
5591             },
5592
5593             "last" : function(c){
5594                 return c[c.length-1] || [];
5595             },
5596
5597             "has" : function(c, ss){
5598                 var s = Roo.DomQuery.select;
5599                 var r = [], ri = -1;
5600                 for(var i = 0, ci; ci = c[i]; i++){
5601                     if(s(ss, ci).length > 0){
5602                         r[++ri] = ci;
5603                     }
5604                 }
5605                 return r;
5606             },
5607
5608             "next" : function(c, ss){
5609                 var is = Roo.DomQuery.is;
5610                 var r = [], ri = -1;
5611                 for(var i = 0, ci; ci = c[i]; i++){
5612                     var n = next(ci);
5613                     if(n && is(n, ss)){
5614                         r[++ri] = ci;
5615                     }
5616                 }
5617                 return r;
5618             },
5619
5620             "prev" : function(c, ss){
5621                 var is = Roo.DomQuery.is;
5622                 var r = [], ri = -1;
5623                 for(var i = 0, ci; ci = c[i]; i++){
5624                     var n = prev(ci);
5625                     if(n && is(n, ss)){
5626                         r[++ri] = ci;
5627                     }
5628                 }
5629                 return r;
5630             }
5631         }
5632     };
5633 }();
5634
5635 /**
5636  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5637  * @param {String} path The selector/xpath query
5638  * @param {Node} root (optional) The start of the query (defaults to document).
5639  * @return {Array}
5640  * @member Roo
5641  * @method query
5642  */
5643 Roo.query = Roo.DomQuery.select;
5644 /*
5645  * Based on:
5646  * Ext JS Library 1.1.1
5647  * Copyright(c) 2006-2007, Ext JS, LLC.
5648  *
5649  * Originally Released Under LGPL - original licence link has changed is not relivant.
5650  *
5651  * Fork - LGPL
5652  * <script type="text/javascript">
5653  */
5654
5655 /**
5656  * @class Roo.util.Observable
5657  * Base class that provides a common interface for publishing events. Subclasses are expected to
5658  * to have a property "events" with all the events defined.<br>
5659  * For example:
5660  * <pre><code>
5661  Employee = function(name){
5662     this.name = name;
5663     this.addEvents({
5664         "fired" : true,
5665         "quit" : true
5666     });
5667  }
5668  Roo.extend(Employee, Roo.util.Observable);
5669 </code></pre>
5670  * @param {Object} config properties to use (incuding events / listeners)
5671  */
5672
5673 Roo.util.Observable = function(cfg){
5674     
5675     cfg = cfg|| {};
5676     this.addEvents(cfg.events || {});
5677     if (cfg.events) {
5678         delete cfg.events; // make sure
5679     }
5680      
5681     Roo.apply(this, cfg);
5682     
5683     if(this.listeners){
5684         this.on(this.listeners);
5685         delete this.listeners;
5686     }
5687 };
5688 Roo.util.Observable.prototype = {
5689     /** 
5690  * @cfg {Object} listeners  list of events and functions to call for this object, 
5691  * For example :
5692  * <pre><code>
5693     listeners :  { 
5694        'click' : function(e) {
5695            ..... 
5696         } ,
5697         .... 
5698     } 
5699   </code></pre>
5700  */
5701     
5702     
5703     /**
5704      * Fires the specified event with the passed parameters (minus the event name).
5705      * @param {String} eventName
5706      * @param {Object...} args Variable number of parameters are passed to handlers
5707      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5708      */
5709     fireEvent : function(){
5710         var ce = this.events[arguments[0].toLowerCase()];
5711         if(typeof ce == "object"){
5712             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5713         }else{
5714             return true;
5715         }
5716     },
5717
5718     // private
5719     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5720
5721     /**
5722      * Appends an event handler to this component
5723      * @param {String}   eventName The type of event to listen for
5724      * @param {Function} handler The method the event invokes
5725      * @param {Object}   scope (optional) The scope in which to execute the handler
5726      * function. The handler function's "this" context.
5727      * @param {Object}   options (optional) An object containing handler configuration
5728      * properties. This may contain any of the following properties:<ul>
5729      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5730      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5731      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5732      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5733      * by the specified number of milliseconds. If the event fires again within that time, the original
5734      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5735      * </ul><br>
5736      * <p>
5737      * <b>Combining Options</b><br>
5738      * Using the options argument, it is possible to combine different types of listeners:<br>
5739      * <br>
5740      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5741                 <pre><code>
5742                 el.on('click', this.onClick, this, {
5743                         single: true,
5744                 delay: 100,
5745                 forumId: 4
5746                 });
5747                 </code></pre>
5748      * <p>
5749      * <b>Attaching multiple handlers in 1 call</b><br>
5750      * The method also allows for a single argument to be passed which is a config object containing properties
5751      * which specify multiple handlers.
5752      * <pre><code>
5753                 el.on({
5754                         'click': {
5755                         fn: this.onClick,
5756                         scope: this,
5757                         delay: 100
5758                 }, 
5759                 'mouseover': {
5760                         fn: this.onMouseOver,
5761                         scope: this
5762                 },
5763                 'mouseout': {
5764                         fn: this.onMouseOut,
5765                         scope: this
5766                 }
5767                 });
5768                 </code></pre>
5769      * <p>
5770      * Or a shorthand syntax which passes the same scope object to all handlers:
5771         <pre><code>
5772                 el.on({
5773                         'click': this.onClick,
5774                 'mouseover': this.onMouseOver,
5775                 'mouseout': this.onMouseOut,
5776                 scope: this
5777                 });
5778                 </code></pre>
5779      */
5780     addListener : function(eventName, fn, scope, o){
5781         if(typeof eventName == "object"){
5782             o = eventName;
5783             for(var e in o){
5784                 if(this.filterOptRe.test(e)){
5785                     continue;
5786                 }
5787                 if(typeof o[e] == "function"){
5788                     // shared options
5789                     this.addListener(e, o[e], o.scope,  o);
5790                 }else{
5791                     // individual options
5792                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5793                 }
5794             }
5795             return;
5796         }
5797         o = (!o || typeof o == "boolean") ? {} : o;
5798         eventName = eventName.toLowerCase();
5799         var ce = this.events[eventName] || true;
5800         if(typeof ce == "boolean"){
5801             ce = new Roo.util.Event(this, eventName);
5802             this.events[eventName] = ce;
5803         }
5804         ce.addListener(fn, scope, o);
5805     },
5806
5807     /**
5808      * Removes a listener
5809      * @param {String}   eventName     The type of event to listen for
5810      * @param {Function} handler        The handler to remove
5811      * @param {Object}   scope  (optional) The scope (this object) for the handler
5812      */
5813     removeListener : function(eventName, fn, scope){
5814         var ce = this.events[eventName.toLowerCase()];
5815         if(typeof ce == "object"){
5816             ce.removeListener(fn, scope);
5817         }
5818     },
5819
5820     /**
5821      * Removes all listeners for this object
5822      */
5823     purgeListeners : function(){
5824         for(var evt in this.events){
5825             if(typeof this.events[evt] == "object"){
5826                  this.events[evt].clearListeners();
5827             }
5828         }
5829     },
5830
5831     relayEvents : function(o, events){
5832         var createHandler = function(ename){
5833             return function(){
5834                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5835             };
5836         };
5837         for(var i = 0, len = events.length; i < len; i++){
5838             var ename = events[i];
5839             if(!this.events[ename]){ this.events[ename] = true; };
5840             o.on(ename, createHandler(ename), this);
5841         }
5842     },
5843
5844     /**
5845      * Used to define events on this Observable
5846      * @param {Object} object The object with the events defined
5847      */
5848     addEvents : function(o){
5849         if(!this.events){
5850             this.events = {};
5851         }
5852         Roo.applyIf(this.events, o);
5853     },
5854
5855     /**
5856      * Checks to see if this object has any listeners for a specified event
5857      * @param {String} eventName The name of the event to check for
5858      * @return {Boolean} True if the event is being listened for, else false
5859      */
5860     hasListener : function(eventName){
5861         var e = this.events[eventName];
5862         return typeof e == "object" && e.listeners.length > 0;
5863     }
5864 };
5865 /**
5866  * Appends an event handler to this element (shorthand for addListener)
5867  * @param {String}   eventName     The type of event to listen for
5868  * @param {Function} handler        The method the event invokes
5869  * @param {Object}   scope (optional) The scope in which to execute the handler
5870  * function. The handler function's "this" context.
5871  * @param {Object}   options  (optional)
5872  * @method
5873  */
5874 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5875 /**
5876  * Removes a listener (shorthand for removeListener)
5877  * @param {String}   eventName     The type of event to listen for
5878  * @param {Function} handler        The handler to remove
5879  * @param {Object}   scope  (optional) The scope (this object) for the handler
5880  * @method
5881  */
5882 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5883
5884 /**
5885  * Starts capture on the specified Observable. All events will be passed
5886  * to the supplied function with the event name + standard signature of the event
5887  * <b>before</b> the event is fired. If the supplied function returns false,
5888  * the event will not fire.
5889  * @param {Observable} o The Observable to capture
5890  * @param {Function} fn The function to call
5891  * @param {Object} scope (optional) The scope (this object) for the fn
5892  * @static
5893  */
5894 Roo.util.Observable.capture = function(o, fn, scope){
5895     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5896 };
5897
5898 /**
5899  * Removes <b>all</b> added captures from the Observable.
5900  * @param {Observable} o The Observable to release
5901  * @static
5902  */
5903 Roo.util.Observable.releaseCapture = function(o){
5904     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5905 };
5906
5907 (function(){
5908
5909     var createBuffered = function(h, o, scope){
5910         var task = new Roo.util.DelayedTask();
5911         return function(){
5912             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5913         };
5914     };
5915
5916     var createSingle = function(h, e, fn, scope){
5917         return function(){
5918             e.removeListener(fn, scope);
5919             return h.apply(scope, arguments);
5920         };
5921     };
5922
5923     var createDelayed = function(h, o, scope){
5924         return function(){
5925             var args = Array.prototype.slice.call(arguments, 0);
5926             setTimeout(function(){
5927                 h.apply(scope, args);
5928             }, o.delay || 10);
5929         };
5930     };
5931
5932     Roo.util.Event = function(obj, name){
5933         this.name = name;
5934         this.obj = obj;
5935         this.listeners = [];
5936     };
5937
5938     Roo.util.Event.prototype = {
5939         addListener : function(fn, scope, options){
5940             var o = options || {};
5941             scope = scope || this.obj;
5942             if(!this.isListening(fn, scope)){
5943                 var l = {fn: fn, scope: scope, options: o};
5944                 var h = fn;
5945                 if(o.delay){
5946                     h = createDelayed(h, o, scope);
5947                 }
5948                 if(o.single){
5949                     h = createSingle(h, this, fn, scope);
5950                 }
5951                 if(o.buffer){
5952                     h = createBuffered(h, o, scope);
5953                 }
5954                 l.fireFn = h;
5955                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5956                     this.listeners.push(l);
5957                 }else{
5958                     this.listeners = this.listeners.slice(0);
5959                     this.listeners.push(l);
5960                 }
5961             }
5962         },
5963
5964         findListener : function(fn, scope){
5965             scope = scope || this.obj;
5966             var ls = this.listeners;
5967             for(var i = 0, len = ls.length; i < len; i++){
5968                 var l = ls[i];
5969                 if(l.fn == fn && l.scope == scope){
5970                     return i;
5971                 }
5972             }
5973             return -1;
5974         },
5975
5976         isListening : function(fn, scope){
5977             return this.findListener(fn, scope) != -1;
5978         },
5979
5980         removeListener : function(fn, scope){
5981             var index;
5982             if((index = this.findListener(fn, scope)) != -1){
5983                 if(!this.firing){
5984                     this.listeners.splice(index, 1);
5985                 }else{
5986                     this.listeners = this.listeners.slice(0);
5987                     this.listeners.splice(index, 1);
5988                 }
5989                 return true;
5990             }
5991             return false;
5992         },
5993
5994         clearListeners : function(){
5995             this.listeners = [];
5996         },
5997
5998         fire : function(){
5999             var ls = this.listeners, scope, len = ls.length;
6000             if(len > 0){
6001                 this.firing = true;
6002                 var args = Array.prototype.slice.call(arguments, 0);
6003                 for(var i = 0; i < len; i++){
6004                     var l = ls[i];
6005                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6006                         this.firing = false;
6007                         return false;
6008                     }
6009                 }
6010                 this.firing = false;
6011             }
6012             return true;
6013         }
6014     };
6015 })();/*
6016  * Based on:
6017  * Ext JS Library 1.1.1
6018  * Copyright(c) 2006-2007, Ext JS, LLC.
6019  *
6020  * Originally Released Under LGPL - original licence link has changed is not relivant.
6021  *
6022  * Fork - LGPL
6023  * <script type="text/javascript">
6024  */
6025
6026 /**
6027  * @class Roo.EventManager
6028  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6029  * several useful events directly.
6030  * See {@link Roo.EventObject} for more details on normalized event objects.
6031  * @singleton
6032  */
6033 Roo.EventManager = function(){
6034     var docReadyEvent, docReadyProcId, docReadyState = false;
6035     var resizeEvent, resizeTask, textEvent, textSize;
6036     var E = Roo.lib.Event;
6037     var D = Roo.lib.Dom;
6038
6039
6040     var fireDocReady = function(){
6041         if(!docReadyState){
6042             docReadyState = true;
6043             Roo.isReady = true;
6044             if(docReadyProcId){
6045                 clearInterval(docReadyProcId);
6046             }
6047             if(Roo.isGecko || Roo.isOpera) {
6048                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6049             }
6050             if(Roo.isIE){
6051                 var defer = document.getElementById("ie-deferred-loader");
6052                 if(defer){
6053                     defer.onreadystatechange = null;
6054                     defer.parentNode.removeChild(defer);
6055                 }
6056             }
6057             if(docReadyEvent){
6058                 docReadyEvent.fire();
6059                 docReadyEvent.clearListeners();
6060             }
6061         }
6062     };
6063     
6064     var initDocReady = function(){
6065         docReadyEvent = new Roo.util.Event();
6066         if(Roo.isGecko || Roo.isOpera) {
6067             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6068         }else if(Roo.isIE){
6069             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6070             var defer = document.getElementById("ie-deferred-loader");
6071             defer.onreadystatechange = function(){
6072                 if(this.readyState == "complete"){
6073                     fireDocReady();
6074                 }
6075             };
6076         }else if(Roo.isSafari){ 
6077             docReadyProcId = setInterval(function(){
6078                 var rs = document.readyState;
6079                 if(rs == "complete") {
6080                     fireDocReady();     
6081                  }
6082             }, 10);
6083         }
6084         // no matter what, make sure it fires on load
6085         E.on(window, "load", fireDocReady);
6086     };
6087
6088     var createBuffered = function(h, o){
6089         var task = new Roo.util.DelayedTask(h);
6090         return function(e){
6091             // create new event object impl so new events don't wipe out properties
6092             e = new Roo.EventObjectImpl(e);
6093             task.delay(o.buffer, h, null, [e]);
6094         };
6095     };
6096
6097     var createSingle = function(h, el, ename, fn){
6098         return function(e){
6099             Roo.EventManager.removeListener(el, ename, fn);
6100             h(e);
6101         };
6102     };
6103
6104     var createDelayed = function(h, o){
6105         return function(e){
6106             // create new event object impl so new events don't wipe out properties
6107             e = new Roo.EventObjectImpl(e);
6108             setTimeout(function(){
6109                 h(e);
6110             }, o.delay || 10);
6111         };
6112     };
6113
6114     var listen = function(element, ename, opt, fn, scope){
6115         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6116         fn = fn || o.fn; scope = scope || o.scope;
6117         var el = Roo.getDom(element);
6118         if(!el){
6119             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6120         }
6121         var h = function(e){
6122             e = Roo.EventObject.setEvent(e);
6123             var t;
6124             if(o.delegate){
6125                 t = e.getTarget(o.delegate, el);
6126                 if(!t){
6127                     return;
6128                 }
6129             }else{
6130                 t = e.target;
6131             }
6132             if(o.stopEvent === true){
6133                 e.stopEvent();
6134             }
6135             if(o.preventDefault === true){
6136                e.preventDefault();
6137             }
6138             if(o.stopPropagation === true){
6139                 e.stopPropagation();
6140             }
6141
6142             if(o.normalized === false){
6143                 e = e.browserEvent;
6144             }
6145
6146             fn.call(scope || el, e, t, o);
6147         };
6148         if(o.delay){
6149             h = createDelayed(h, o);
6150         }
6151         if(o.single){
6152             h = createSingle(h, el, ename, fn);
6153         }
6154         if(o.buffer){
6155             h = createBuffered(h, o);
6156         }
6157         fn._handlers = fn._handlers || [];
6158         fn._handlers.push([Roo.id(el), ename, h]);
6159
6160         E.on(el, ename, h);
6161         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6162             el.addEventListener("DOMMouseScroll", h, false);
6163             E.on(window, 'unload', function(){
6164                 el.removeEventListener("DOMMouseScroll", h, false);
6165             });
6166         }
6167         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6168             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6169         }
6170         return h;
6171     };
6172
6173     var stopListening = function(el, ename, fn){
6174         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6175         if(hds){
6176             for(var i = 0, len = hds.length; i < len; i++){
6177                 var h = hds[i];
6178                 if(h[0] == id && h[1] == ename){
6179                     hd = h[2];
6180                     hds.splice(i, 1);
6181                     break;
6182                 }
6183             }
6184         }
6185         E.un(el, ename, hd);
6186         el = Roo.getDom(el);
6187         if(ename == "mousewheel" && el.addEventListener){
6188             el.removeEventListener("DOMMouseScroll", hd, false);
6189         }
6190         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6191             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6192         }
6193     };
6194
6195     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6196     
6197     var pub = {
6198         
6199         
6200         /** 
6201          * Fix for doc tools
6202          * @scope Roo.EventManager
6203          */
6204         
6205         
6206         /** 
6207          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6208          * object with a Roo.EventObject
6209          * @param {Function} fn        The method the event invokes
6210          * @param {Object}   scope    An object that becomes the scope of the handler
6211          * @param {boolean}  override If true, the obj passed in becomes
6212          *                             the execution scope of the listener
6213          * @return {Function} The wrapped function
6214          * @deprecated
6215          */
6216         wrap : function(fn, scope, override){
6217             return function(e){
6218                 Roo.EventObject.setEvent(e);
6219                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6220             };
6221         },
6222         
6223         /**
6224      * Appends an event handler to an element (shorthand for addListener)
6225      * @param {String/HTMLElement}   element        The html element or id to assign the
6226      * @param {String}   eventName The type of event to listen for
6227      * @param {Function} handler The method the event invokes
6228      * @param {Object}   scope (optional) The scope in which to execute the handler
6229      * function. The handler function's "this" context.
6230      * @param {Object}   options (optional) An object containing handler configuration
6231      * properties. This may contain any of the following properties:<ul>
6232      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6233      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6234      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6235      * <li>preventDefault {Boolean} True to prevent the default action</li>
6236      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6237      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6238      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6239      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6240      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6241      * by the specified number of milliseconds. If the event fires again within that time, the original
6242      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6243      * </ul><br>
6244      * <p>
6245      * <b>Combining Options</b><br>
6246      * Using the options argument, it is possible to combine different types of listeners:<br>
6247      * <br>
6248      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6249      * Code:<pre><code>
6250 el.on('click', this.onClick, this, {
6251     single: true,
6252     delay: 100,
6253     stopEvent : true,
6254     forumId: 4
6255 });</code></pre>
6256      * <p>
6257      * <b>Attaching multiple handlers in 1 call</b><br>
6258       * The method also allows for a single argument to be passed which is a config object containing properties
6259      * which specify multiple handlers.
6260      * <p>
6261      * Code:<pre><code>
6262 el.on({
6263     'click' : {
6264         fn: this.onClick
6265         scope: this,
6266         delay: 100
6267     },
6268     'mouseover' : {
6269         fn: this.onMouseOver
6270         scope: this
6271     },
6272     'mouseout' : {
6273         fn: this.onMouseOut
6274         scope: this
6275     }
6276 });</code></pre>
6277      * <p>
6278      * Or a shorthand syntax:<br>
6279      * Code:<pre><code>
6280 el.on({
6281     'click' : this.onClick,
6282     'mouseover' : this.onMouseOver,
6283     'mouseout' : this.onMouseOut
6284     scope: this
6285 });</code></pre>
6286      */
6287         addListener : function(element, eventName, fn, scope, options){
6288             if(typeof eventName == "object"){
6289                 var o = eventName;
6290                 for(var e in o){
6291                     if(propRe.test(e)){
6292                         continue;
6293                     }
6294                     if(typeof o[e] == "function"){
6295                         // shared options
6296                         listen(element, e, o, o[e], o.scope);
6297                     }else{
6298                         // individual options
6299                         listen(element, e, o[e]);
6300                     }
6301                 }
6302                 return;
6303             }
6304             return listen(element, eventName, options, fn, scope);
6305         },
6306         
6307         /**
6308          * Removes an event handler
6309          *
6310          * @param {String/HTMLElement}   element        The id or html element to remove the 
6311          *                             event from
6312          * @param {String}   eventName     The type of event
6313          * @param {Function} fn
6314          * @return {Boolean} True if a listener was actually removed
6315          */
6316         removeListener : function(element, eventName, fn){
6317             return stopListening(element, eventName, fn);
6318         },
6319         
6320         /**
6321          * Fires when the document is ready (before onload and before images are loaded). Can be 
6322          * accessed shorthanded Roo.onReady().
6323          * @param {Function} fn        The method the event invokes
6324          * @param {Object}   scope    An  object that becomes the scope of the handler
6325          * @param {boolean}  options
6326          */
6327         onDocumentReady : function(fn, scope, options){
6328             if(docReadyState){ // if it already fired
6329                 docReadyEvent.addListener(fn, scope, options);
6330                 docReadyEvent.fire();
6331                 docReadyEvent.clearListeners();
6332                 return;
6333             }
6334             if(!docReadyEvent){
6335                 initDocReady();
6336             }
6337             docReadyEvent.addListener(fn, scope, options);
6338         },
6339         
6340         /**
6341          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6342          * @param {Function} fn        The method the event invokes
6343          * @param {Object}   scope    An object that becomes the scope of the handler
6344          * @param {boolean}  options
6345          */
6346         onWindowResize : function(fn, scope, options){
6347             if(!resizeEvent){
6348                 resizeEvent = new Roo.util.Event();
6349                 resizeTask = new Roo.util.DelayedTask(function(){
6350                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6351                 });
6352                 E.on(window, "resize", function(){
6353                     if(Roo.isIE){
6354                         resizeTask.delay(50);
6355                     }else{
6356                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6357                     }
6358                 });
6359             }
6360             resizeEvent.addListener(fn, scope, options);
6361         },
6362
6363         /**
6364          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6365          * @param {Function} fn        The method the event invokes
6366          * @param {Object}   scope    An object that becomes the scope of the handler
6367          * @param {boolean}  options
6368          */
6369         onTextResize : function(fn, scope, options){
6370             if(!textEvent){
6371                 textEvent = new Roo.util.Event();
6372                 var textEl = new Roo.Element(document.createElement('div'));
6373                 textEl.dom.className = 'x-text-resize';
6374                 textEl.dom.innerHTML = 'X';
6375                 textEl.appendTo(document.body);
6376                 textSize = textEl.dom.offsetHeight;
6377                 setInterval(function(){
6378                     if(textEl.dom.offsetHeight != textSize){
6379                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6380                     }
6381                 }, this.textResizeInterval);
6382             }
6383             textEvent.addListener(fn, scope, options);
6384         },
6385
6386         /**
6387          * Removes the passed window resize listener.
6388          * @param {Function} fn        The method the event invokes
6389          * @param {Object}   scope    The scope of handler
6390          */
6391         removeResizeListener : function(fn, scope){
6392             if(resizeEvent){
6393                 resizeEvent.removeListener(fn, scope);
6394             }
6395         },
6396
6397         // private
6398         fireResize : function(){
6399             if(resizeEvent){
6400                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6401             }   
6402         },
6403         /**
6404          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6405          */
6406         ieDeferSrc : false,
6407         /**
6408          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6409          */
6410         textResizeInterval : 50
6411     };
6412     
6413     /**
6414      * Fix for doc tools
6415      * @scopeAlias pub=Roo.EventManager
6416      */
6417     
6418      /**
6419      * Appends an event handler to an element (shorthand for addListener)
6420      * @param {String/HTMLElement}   element        The html element or id to assign the
6421      * @param {String}   eventName The type of event to listen for
6422      * @param {Function} handler The method the event invokes
6423      * @param {Object}   scope (optional) The scope in which to execute the handler
6424      * function. The handler function's "this" context.
6425      * @param {Object}   options (optional) An object containing handler configuration
6426      * properties. This may contain any of the following properties:<ul>
6427      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6428      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6429      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6430      * <li>preventDefault {Boolean} True to prevent the default action</li>
6431      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6432      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6433      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6434      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6435      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6436      * by the specified number of milliseconds. If the event fires again within that time, the original
6437      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6438      * </ul><br>
6439      * <p>
6440      * <b>Combining Options</b><br>
6441      * Using the options argument, it is possible to combine different types of listeners:<br>
6442      * <br>
6443      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6444      * Code:<pre><code>
6445 el.on('click', this.onClick, this, {
6446     single: true,
6447     delay: 100,
6448     stopEvent : true,
6449     forumId: 4
6450 });</code></pre>
6451      * <p>
6452      * <b>Attaching multiple handlers in 1 call</b><br>
6453       * The method also allows for a single argument to be passed which is a config object containing properties
6454      * which specify multiple handlers.
6455      * <p>
6456      * Code:<pre><code>
6457 el.on({
6458     'click' : {
6459         fn: this.onClick
6460         scope: this,
6461         delay: 100
6462     },
6463     'mouseover' : {
6464         fn: this.onMouseOver
6465         scope: this
6466     },
6467     'mouseout' : {
6468         fn: this.onMouseOut
6469         scope: this
6470     }
6471 });</code></pre>
6472      * <p>
6473      * Or a shorthand syntax:<br>
6474      * Code:<pre><code>
6475 el.on({
6476     'click' : this.onClick,
6477     'mouseover' : this.onMouseOver,
6478     'mouseout' : this.onMouseOut
6479     scope: this
6480 });</code></pre>
6481      */
6482     pub.on = pub.addListener;
6483     pub.un = pub.removeListener;
6484
6485     pub.stoppedMouseDownEvent = new Roo.util.Event();
6486     return pub;
6487 }();
6488 /**
6489   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6490   * @param {Function} fn        The method the event invokes
6491   * @param {Object}   scope    An  object that becomes the scope of the handler
6492   * @param {boolean}  override If true, the obj passed in becomes
6493   *                             the execution scope of the listener
6494   * @member Roo
6495   * @method onReady
6496  */
6497 Roo.onReady = Roo.EventManager.onDocumentReady;
6498
6499 Roo.onReady(function(){
6500     var bd = Roo.get(document.body);
6501     if(!bd){ return; }
6502
6503     var cls = [
6504             Roo.isIE ? "roo-ie"
6505             : Roo.isGecko ? "roo-gecko"
6506             : Roo.isOpera ? "roo-opera"
6507             : Roo.isSafari ? "roo-safari" : ""];
6508
6509     if(Roo.isMac){
6510         cls.push("roo-mac");
6511     }
6512     if(Roo.isLinux){
6513         cls.push("roo-linux");
6514     }
6515     if(Roo.isBorderBox){
6516         cls.push('roo-border-box');
6517     }
6518     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6519         var p = bd.dom.parentNode;
6520         if(p){
6521             p.className += ' roo-strict';
6522         }
6523     }
6524     bd.addClass(cls.join(' '));
6525 });
6526
6527 /**
6528  * @class Roo.EventObject
6529  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6530  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6531  * Example:
6532  * <pre><code>
6533  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6534     e.preventDefault();
6535     var target = e.getTarget();
6536     ...
6537  }
6538  var myDiv = Roo.get("myDiv");
6539  myDiv.on("click", handleClick);
6540  //or
6541  Roo.EventManager.on("myDiv", 'click', handleClick);
6542  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6543  </code></pre>
6544  * @singleton
6545  */
6546 Roo.EventObject = function(){
6547     
6548     var E = Roo.lib.Event;
6549     
6550     // safari keypress events for special keys return bad keycodes
6551     var safariKeys = {
6552         63234 : 37, // left
6553         63235 : 39, // right
6554         63232 : 38, // up
6555         63233 : 40, // down
6556         63276 : 33, // page up
6557         63277 : 34, // page down
6558         63272 : 46, // delete
6559         63273 : 36, // home
6560         63275 : 35  // end
6561     };
6562
6563     // normalize button clicks
6564     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6565                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6566
6567     Roo.EventObjectImpl = function(e){
6568         if(e){
6569             this.setEvent(e.browserEvent || e);
6570         }
6571     };
6572     Roo.EventObjectImpl.prototype = {
6573         /**
6574          * Used to fix doc tools.
6575          * @scope Roo.EventObject.prototype
6576          */
6577             
6578
6579         
6580         
6581         /** The normal browser event */
6582         browserEvent : null,
6583         /** The button pressed in a mouse event */
6584         button : -1,
6585         /** True if the shift key was down during the event */
6586         shiftKey : false,
6587         /** True if the control key was down during the event */
6588         ctrlKey : false,
6589         /** True if the alt key was down during the event */
6590         altKey : false,
6591
6592         /** Key constant 
6593         * @type Number */
6594         BACKSPACE : 8,
6595         /** Key constant 
6596         * @type Number */
6597         TAB : 9,
6598         /** Key constant 
6599         * @type Number */
6600         RETURN : 13,
6601         /** Key constant 
6602         * @type Number */
6603         ENTER : 13,
6604         /** Key constant 
6605         * @type Number */
6606         SHIFT : 16,
6607         /** Key constant 
6608         * @type Number */
6609         CONTROL : 17,
6610         /** Key constant 
6611         * @type Number */
6612         ESC : 27,
6613         /** Key constant 
6614         * @type Number */
6615         SPACE : 32,
6616         /** Key constant 
6617         * @type Number */
6618         PAGEUP : 33,
6619         /** Key constant 
6620         * @type Number */
6621         PAGEDOWN : 34,
6622         /** Key constant 
6623         * @type Number */
6624         END : 35,
6625         /** Key constant 
6626         * @type Number */
6627         HOME : 36,
6628         /** Key constant 
6629         * @type Number */
6630         LEFT : 37,
6631         /** Key constant 
6632         * @type Number */
6633         UP : 38,
6634         /** Key constant 
6635         * @type Number */
6636         RIGHT : 39,
6637         /** Key constant 
6638         * @type Number */
6639         DOWN : 40,
6640         /** Key constant 
6641         * @type Number */
6642         DELETE : 46,
6643         /** Key constant 
6644         * @type Number */
6645         F5 : 116,
6646
6647            /** @private */
6648         setEvent : function(e){
6649             if(e == this || (e && e.browserEvent)){ // already wrapped
6650                 return e;
6651             }
6652             this.browserEvent = e;
6653             if(e){
6654                 // normalize buttons
6655                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6656                 if(e.type == 'click' && this.button == -1){
6657                     this.button = 0;
6658                 }
6659                 this.type = e.type;
6660                 this.shiftKey = e.shiftKey;
6661                 // mac metaKey behaves like ctrlKey
6662                 this.ctrlKey = e.ctrlKey || e.metaKey;
6663                 this.altKey = e.altKey;
6664                 // in getKey these will be normalized for the mac
6665                 this.keyCode = e.keyCode;
6666                 // keyup warnings on firefox.
6667                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6668                 // cache the target for the delayed and or buffered events
6669                 this.target = E.getTarget(e);
6670                 // same for XY
6671                 this.xy = E.getXY(e);
6672             }else{
6673                 this.button = -1;
6674                 this.shiftKey = false;
6675                 this.ctrlKey = false;
6676                 this.altKey = false;
6677                 this.keyCode = 0;
6678                 this.charCode =0;
6679                 this.target = null;
6680                 this.xy = [0, 0];
6681             }
6682             return this;
6683         },
6684
6685         /**
6686          * Stop the event (preventDefault and stopPropagation)
6687          */
6688         stopEvent : function(){
6689             if(this.browserEvent){
6690                 if(this.browserEvent.type == 'mousedown'){
6691                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6692                 }
6693                 E.stopEvent(this.browserEvent);
6694             }
6695         },
6696
6697         /**
6698          * Prevents the browsers default handling of the event.
6699          */
6700         preventDefault : function(){
6701             if(this.browserEvent){
6702                 E.preventDefault(this.browserEvent);
6703             }
6704         },
6705
6706         /** @private */
6707         isNavKeyPress : function(){
6708             var k = this.keyCode;
6709             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6710             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6711         },
6712
6713         isSpecialKey : function(){
6714             var k = this.keyCode;
6715             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6716             (k == 16) || (k == 17) ||
6717             (k >= 18 && k <= 20) ||
6718             (k >= 33 && k <= 35) ||
6719             (k >= 36 && k <= 39) ||
6720             (k >= 44 && k <= 45);
6721         },
6722         /**
6723          * Cancels bubbling of the event.
6724          */
6725         stopPropagation : function(){
6726             if(this.browserEvent){
6727                 if(this.type == 'mousedown'){
6728                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6729                 }
6730                 E.stopPropagation(this.browserEvent);
6731             }
6732         },
6733
6734         /**
6735          * Gets the key code for the event.
6736          * @return {Number}
6737          */
6738         getCharCode : function(){
6739             return this.charCode || this.keyCode;
6740         },
6741
6742         /**
6743          * Returns a normalized keyCode for the event.
6744          * @return {Number} The key code
6745          */
6746         getKey : function(){
6747             var k = this.keyCode || this.charCode;
6748             return Roo.isSafari ? (safariKeys[k] || k) : k;
6749         },
6750
6751         /**
6752          * Gets the x coordinate of the event.
6753          * @return {Number}
6754          */
6755         getPageX : function(){
6756             return this.xy[0];
6757         },
6758
6759         /**
6760          * Gets the y coordinate of the event.
6761          * @return {Number}
6762          */
6763         getPageY : function(){
6764             return this.xy[1];
6765         },
6766
6767         /**
6768          * Gets the time of the event.
6769          * @return {Number}
6770          */
6771         getTime : function(){
6772             if(this.browserEvent){
6773                 return E.getTime(this.browserEvent);
6774             }
6775             return null;
6776         },
6777
6778         /**
6779          * Gets the page coordinates of the event.
6780          * @return {Array} The xy values like [x, y]
6781          */
6782         getXY : function(){
6783             return this.xy;
6784         },
6785
6786         /**
6787          * Gets the target for the event.
6788          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6789          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6790                 search as a number or element (defaults to 10 || document.body)
6791          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6792          * @return {HTMLelement}
6793          */
6794         getTarget : function(selector, maxDepth, returnEl){
6795             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6796         },
6797         /**
6798          * Gets the related target.
6799          * @return {HTMLElement}
6800          */
6801         getRelatedTarget : function(){
6802             if(this.browserEvent){
6803                 return E.getRelatedTarget(this.browserEvent);
6804             }
6805             return null;
6806         },
6807
6808         /**
6809          * Normalizes mouse wheel delta across browsers
6810          * @return {Number} The delta
6811          */
6812         getWheelDelta : function(){
6813             var e = this.browserEvent;
6814             var delta = 0;
6815             if(e.wheelDelta){ /* IE/Opera. */
6816                 delta = e.wheelDelta/120;
6817             }else if(e.detail){ /* Mozilla case. */
6818                 delta = -e.detail/3;
6819             }
6820             return delta;
6821         },
6822
6823         /**
6824          * Returns true if the control, meta, shift or alt key was pressed during this event.
6825          * @return {Boolean}
6826          */
6827         hasModifier : function(){
6828             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6829         },
6830
6831         /**
6832          * Returns true if the target of this event equals el or is a child of el
6833          * @param {String/HTMLElement/Element} el
6834          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6835          * @return {Boolean}
6836          */
6837         within : function(el, related){
6838             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6839             return t && Roo.fly(el).contains(t);
6840         },
6841
6842         getPoint : function(){
6843             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6844         }
6845     };
6846
6847     return new Roo.EventObjectImpl();
6848 }();
6849             
6850     /*
6851  * Based on:
6852  * Ext JS Library 1.1.1
6853  * Copyright(c) 2006-2007, Ext JS, LLC.
6854  *
6855  * Originally Released Under LGPL - original licence link has changed is not relivant.
6856  *
6857  * Fork - LGPL
6858  * <script type="text/javascript">
6859  */
6860
6861  
6862 // was in Composite Element!??!?!
6863  
6864 (function(){
6865     var D = Roo.lib.Dom;
6866     var E = Roo.lib.Event;
6867     var A = Roo.lib.Anim;
6868
6869     // local style camelizing for speed
6870     var propCache = {};
6871     var camelRe = /(-[a-z])/gi;
6872     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6873     var view = document.defaultView;
6874
6875 /**
6876  * @class Roo.Element
6877  * Represents an Element in the DOM.<br><br>
6878  * Usage:<br>
6879 <pre><code>
6880 var el = Roo.get("my-div");
6881
6882 // or with getEl
6883 var el = getEl("my-div");
6884
6885 // or with a DOM element
6886 var el = Roo.get(myDivElement);
6887 </code></pre>
6888  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6889  * each call instead of constructing a new one.<br><br>
6890  * <b>Animations</b><br />
6891  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6892  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6893 <pre>
6894 Option    Default   Description
6895 --------- --------  ---------------------------------------------
6896 duration  .35       The duration of the animation in seconds
6897 easing    easeOut   The YUI easing method
6898 callback  none      A function to execute when the anim completes
6899 scope     this      The scope (this) of the callback function
6900 </pre>
6901 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6902 * manipulate the animation. Here's an example:
6903 <pre><code>
6904 var el = Roo.get("my-div");
6905
6906 // no animation
6907 el.setWidth(100);
6908
6909 // default animation
6910 el.setWidth(100, true);
6911
6912 // animation with some options set
6913 el.setWidth(100, {
6914     duration: 1,
6915     callback: this.foo,
6916     scope: this
6917 });
6918
6919 // using the "anim" property to get the Anim object
6920 var opt = {
6921     duration: 1,
6922     callback: this.foo,
6923     scope: this
6924 };
6925 el.setWidth(100, opt);
6926 ...
6927 if(opt.anim.isAnimated()){
6928     opt.anim.stop();
6929 }
6930 </code></pre>
6931 * <b> Composite (Collections of) Elements</b><br />
6932  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6933  * @constructor Create a new Element directly.
6934  * @param {String/HTMLElement} element
6935  * @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).
6936  */
6937     Roo.Element = function(element, forceNew){
6938         var dom = typeof element == "string" ?
6939                 document.getElementById(element) : element;
6940         if(!dom){ // invalid id/element
6941             return null;
6942         }
6943         var id = dom.id;
6944         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6945             return Roo.Element.cache[id];
6946         }
6947
6948         /**
6949          * The DOM element
6950          * @type HTMLElement
6951          */
6952         this.dom = dom;
6953
6954         /**
6955          * The DOM element ID
6956          * @type String
6957          */
6958         this.id = id || Roo.id(dom);
6959     };
6960
6961     var El = Roo.Element;
6962
6963     El.prototype = {
6964         /**
6965          * The element's default display mode  (defaults to "")
6966          * @type String
6967          */
6968         originalDisplay : "",
6969
6970         visibilityMode : 1,
6971         /**
6972          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6973          * @type String
6974          */
6975         defaultUnit : "px",
6976         /**
6977          * Sets the element's visibility mode. When setVisible() is called it
6978          * will use this to determine whether to set the visibility or the display property.
6979          * @param visMode Element.VISIBILITY or Element.DISPLAY
6980          * @return {Roo.Element} this
6981          */
6982         setVisibilityMode : function(visMode){
6983             this.visibilityMode = visMode;
6984             return this;
6985         },
6986         /**
6987          * Convenience method for setVisibilityMode(Element.DISPLAY)
6988          * @param {String} display (optional) What to set display to when visible
6989          * @return {Roo.Element} this
6990          */
6991         enableDisplayMode : function(display){
6992             this.setVisibilityMode(El.DISPLAY);
6993             if(typeof display != "undefined") this.originalDisplay = display;
6994             return this;
6995         },
6996
6997         /**
6998          * 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)
6999          * @param {String} selector The simple selector to test
7000          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7001                 search as a number or element (defaults to 10 || document.body)
7002          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7003          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7004          */
7005         findParent : function(simpleSelector, maxDepth, returnEl){
7006             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7007             maxDepth = maxDepth || 50;
7008             if(typeof maxDepth != "number"){
7009                 stopEl = Roo.getDom(maxDepth);
7010                 maxDepth = 10;
7011             }
7012             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7013                 if(dq.is(p, simpleSelector)){
7014                     return returnEl ? Roo.get(p) : p;
7015                 }
7016                 depth++;
7017                 p = p.parentNode;
7018             }
7019             return null;
7020         },
7021
7022
7023         /**
7024          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7025          * @param {String} selector The simple selector to test
7026          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7027                 search as a number or element (defaults to 10 || document.body)
7028          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7029          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7030          */
7031         findParentNode : function(simpleSelector, maxDepth, returnEl){
7032             var p = Roo.fly(this.dom.parentNode, '_internal');
7033             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7034         },
7035
7036         /**
7037          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7038          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7039          * @param {String} selector The simple selector to test
7040          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7041                 search as a number or element (defaults to 10 || document.body)
7042          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7043          */
7044         up : function(simpleSelector, maxDepth){
7045             return this.findParentNode(simpleSelector, maxDepth, true);
7046         },
7047
7048
7049
7050         /**
7051          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7052          * @param {String} selector The simple selector to test
7053          * @return {Boolean} True if this element matches the selector, else false
7054          */
7055         is : function(simpleSelector){
7056             return Roo.DomQuery.is(this.dom, simpleSelector);
7057         },
7058
7059         /**
7060          * Perform animation on this element.
7061          * @param {Object} args The YUI animation control args
7062          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7063          * @param {Function} onComplete (optional) Function to call when animation completes
7064          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7065          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7066          * @return {Roo.Element} this
7067          */
7068         animate : function(args, duration, onComplete, easing, animType){
7069             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7070             return this;
7071         },
7072
7073         /*
7074          * @private Internal animation call
7075          */
7076         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7077             animType = animType || 'run';
7078             opt = opt || {};
7079             var anim = Roo.lib.Anim[animType](
7080                 this.dom, args,
7081                 (opt.duration || defaultDur) || .35,
7082                 (opt.easing || defaultEase) || 'easeOut',
7083                 function(){
7084                     Roo.callback(cb, this);
7085                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7086                 },
7087                 this
7088             );
7089             opt.anim = anim;
7090             return anim;
7091         },
7092
7093         // private legacy anim prep
7094         preanim : function(a, i){
7095             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7096         },
7097
7098         /**
7099          * Removes worthless text nodes
7100          * @param {Boolean} forceReclean (optional) By default the element
7101          * keeps track if it has been cleaned already so
7102          * you can call this over and over. However, if you update the element and
7103          * need to force a reclean, you can pass true.
7104          */
7105         clean : function(forceReclean){
7106             if(this.isCleaned && forceReclean !== true){
7107                 return this;
7108             }
7109             var ns = /\S/;
7110             var d = this.dom, n = d.firstChild, ni = -1;
7111             while(n){
7112                 var nx = n.nextSibling;
7113                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7114                     d.removeChild(n);
7115                 }else{
7116                     n.nodeIndex = ++ni;
7117                 }
7118                 n = nx;
7119             }
7120             this.isCleaned = true;
7121             return this;
7122         },
7123
7124         // private
7125         calcOffsetsTo : function(el){
7126             el = Roo.get(el);
7127             var d = el.dom;
7128             var restorePos = false;
7129             if(el.getStyle('position') == 'static'){
7130                 el.position('relative');
7131                 restorePos = true;
7132             }
7133             var x = 0, y =0;
7134             var op = this.dom;
7135             while(op && op != d && op.tagName != 'HTML'){
7136                 x+= op.offsetLeft;
7137                 y+= op.offsetTop;
7138                 op = op.offsetParent;
7139             }
7140             if(restorePos){
7141                 el.position('static');
7142             }
7143             return [x, y];
7144         },
7145
7146         /**
7147          * Scrolls this element into view within the passed container.
7148          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7149          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7150          * @return {Roo.Element} this
7151          */
7152         scrollIntoView : function(container, hscroll){
7153             var c = Roo.getDom(container) || document.body;
7154             var el = this.dom;
7155
7156             var o = this.calcOffsetsTo(c),
7157                 l = o[0],
7158                 t = o[1],
7159                 b = t+el.offsetHeight,
7160                 r = l+el.offsetWidth;
7161
7162             var ch = c.clientHeight;
7163             var ct = parseInt(c.scrollTop, 10);
7164             var cl = parseInt(c.scrollLeft, 10);
7165             var cb = ct + ch;
7166             var cr = cl + c.clientWidth;
7167
7168             if(t < ct){
7169                 c.scrollTop = t;
7170             }else if(b > cb){
7171                 c.scrollTop = b-ch;
7172             }
7173
7174             if(hscroll !== false){
7175                 if(l < cl){
7176                     c.scrollLeft = l;
7177                 }else if(r > cr){
7178                     c.scrollLeft = r-c.clientWidth;
7179                 }
7180             }
7181             return this;
7182         },
7183
7184         // private
7185         scrollChildIntoView : function(child, hscroll){
7186             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7187         },
7188
7189         /**
7190          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7191          * the new height may not be available immediately.
7192          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7193          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7194          * @param {Function} onComplete (optional) Function to call when animation completes
7195          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7196          * @return {Roo.Element} this
7197          */
7198         autoHeight : function(animate, duration, onComplete, easing){
7199             var oldHeight = this.getHeight();
7200             this.clip();
7201             this.setHeight(1); // force clipping
7202             setTimeout(function(){
7203                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7204                 if(!animate){
7205                     this.setHeight(height);
7206                     this.unclip();
7207                     if(typeof onComplete == "function"){
7208                         onComplete();
7209                     }
7210                 }else{
7211                     this.setHeight(oldHeight); // restore original height
7212                     this.setHeight(height, animate, duration, function(){
7213                         this.unclip();
7214                         if(typeof onComplete == "function") onComplete();
7215                     }.createDelegate(this), easing);
7216                 }
7217             }.createDelegate(this), 0);
7218             return this;
7219         },
7220
7221         /**
7222          * Returns true if this element is an ancestor of the passed element
7223          * @param {HTMLElement/String} el The element to check
7224          * @return {Boolean} True if this element is an ancestor of el, else false
7225          */
7226         contains : function(el){
7227             if(!el){return false;}
7228             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7229         },
7230
7231         /**
7232          * Checks whether the element is currently visible using both visibility and display properties.
7233          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7234          * @return {Boolean} True if the element is currently visible, else false
7235          */
7236         isVisible : function(deep) {
7237             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7238             if(deep !== true || !vis){
7239                 return vis;
7240             }
7241             var p = this.dom.parentNode;
7242             while(p && p.tagName.toLowerCase() != "body"){
7243                 if(!Roo.fly(p, '_isVisible').isVisible()){
7244                     return false;
7245                 }
7246                 p = p.parentNode;
7247             }
7248             return true;
7249         },
7250
7251         /**
7252          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7253          * @param {String} selector The CSS selector
7254          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7255          * @return {CompositeElement/CompositeElementLite} The composite element
7256          */
7257         select : function(selector, unique){
7258             return El.select(selector, unique, this.dom);
7259         },
7260
7261         /**
7262          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7263          * @param {String} selector The CSS selector
7264          * @return {Array} An array of the matched nodes
7265          */
7266         query : function(selector, unique){
7267             return Roo.DomQuery.select(selector, this.dom);
7268         },
7269
7270         /**
7271          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7272          * @param {String} selector The CSS selector
7273          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7274          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7275          */
7276         child : function(selector, returnDom){
7277             var n = Roo.DomQuery.selectNode(selector, this.dom);
7278             return returnDom ? n : Roo.get(n);
7279         },
7280
7281         /**
7282          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7283          * @param {String} selector The CSS selector
7284          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7285          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7286          */
7287         down : function(selector, returnDom){
7288             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7289             return returnDom ? n : Roo.get(n);
7290         },
7291
7292         /**
7293          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7294          * @param {String} group The group the DD object is member of
7295          * @param {Object} config The DD config object
7296          * @param {Object} overrides An object containing methods to override/implement on the DD object
7297          * @return {Roo.dd.DD} The DD object
7298          */
7299         initDD : function(group, config, overrides){
7300             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7301             return Roo.apply(dd, overrides);
7302         },
7303
7304         /**
7305          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7306          * @param {String} group The group the DDProxy object is member of
7307          * @param {Object} config The DDProxy config object
7308          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7309          * @return {Roo.dd.DDProxy} The DDProxy object
7310          */
7311         initDDProxy : function(group, config, overrides){
7312             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7313             return Roo.apply(dd, overrides);
7314         },
7315
7316         /**
7317          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7318          * @param {String} group The group the DDTarget object is member of
7319          * @param {Object} config The DDTarget config object
7320          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7321          * @return {Roo.dd.DDTarget} The DDTarget object
7322          */
7323         initDDTarget : function(group, config, overrides){
7324             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7325             return Roo.apply(dd, overrides);
7326         },
7327
7328         /**
7329          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7330          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7331          * @param {Boolean} visible Whether the element is visible
7332          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7333          * @return {Roo.Element} this
7334          */
7335          setVisible : function(visible, animate){
7336             if(!animate || !A){
7337                 if(this.visibilityMode == El.DISPLAY){
7338                     this.setDisplayed(visible);
7339                 }else{
7340                     this.fixDisplay();
7341                     this.dom.style.visibility = visible ? "visible" : "hidden";
7342                 }
7343             }else{
7344                 // closure for composites
7345                 var dom = this.dom;
7346                 var visMode = this.visibilityMode;
7347                 if(visible){
7348                     this.setOpacity(.01);
7349                     this.setVisible(true);
7350                 }
7351                 this.anim({opacity: { to: (visible?1:0) }},
7352                       this.preanim(arguments, 1),
7353                       null, .35, 'easeIn', function(){
7354                          if(!visible){
7355                              if(visMode == El.DISPLAY){
7356                                  dom.style.display = "none";
7357                              }else{
7358                                  dom.style.visibility = "hidden";
7359                              }
7360                              Roo.get(dom).setOpacity(1);
7361                          }
7362                      });
7363             }
7364             return this;
7365         },
7366
7367         /**
7368          * Returns true if display is not "none"
7369          * @return {Boolean}
7370          */
7371         isDisplayed : function() {
7372             return this.getStyle("display") != "none";
7373         },
7374
7375         /**
7376          * Toggles the element's visibility or display, depending on visibility mode.
7377          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7378          * @return {Roo.Element} this
7379          */
7380         toggle : function(animate){
7381             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7382             return this;
7383         },
7384
7385         /**
7386          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7387          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7388          * @return {Roo.Element} this
7389          */
7390         setDisplayed : function(value) {
7391             if(typeof value == "boolean"){
7392                value = value ? this.originalDisplay : "none";
7393             }
7394             this.setStyle("display", value);
7395             return this;
7396         },
7397
7398         /**
7399          * Tries to focus the element. Any exceptions are caught and ignored.
7400          * @return {Roo.Element} this
7401          */
7402         focus : function() {
7403             try{
7404                 this.dom.focus();
7405             }catch(e){}
7406             return this;
7407         },
7408
7409         /**
7410          * Tries to blur the element. Any exceptions are caught and ignored.
7411          * @return {Roo.Element} this
7412          */
7413         blur : function() {
7414             try{
7415                 this.dom.blur();
7416             }catch(e){}
7417             return this;
7418         },
7419
7420         /**
7421          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7422          * @param {String/Array} className The CSS class to add, or an array of classes
7423          * @return {Roo.Element} this
7424          */
7425         addClass : function(className){
7426             if(className instanceof Array){
7427                 for(var i = 0, len = className.length; i < len; i++) {
7428                     this.addClass(className[i]);
7429                 }
7430             }else{
7431                 if(className && !this.hasClass(className)){
7432                     this.dom.className = this.dom.className + " " + className;
7433                 }
7434             }
7435             return this;
7436         },
7437
7438         /**
7439          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7440          * @param {String/Array} className The CSS class to add, or an array of classes
7441          * @return {Roo.Element} this
7442          */
7443         radioClass : function(className){
7444             var siblings = this.dom.parentNode.childNodes;
7445             for(var i = 0; i < siblings.length; i++) {
7446                 var s = siblings[i];
7447                 if(s.nodeType == 1){
7448                     Roo.get(s).removeClass(className);
7449                 }
7450             }
7451             this.addClass(className);
7452             return this;
7453         },
7454
7455         /**
7456          * Removes one or more CSS classes from the element.
7457          * @param {String/Array} className The CSS class to remove, or an array of classes
7458          * @return {Roo.Element} this
7459          */
7460         removeClass : function(className){
7461             if(!className || !this.dom.className){
7462                 return this;
7463             }
7464             if(className instanceof Array){
7465                 for(var i = 0, len = className.length; i < len; i++) {
7466                     this.removeClass(className[i]);
7467                 }
7468             }else{
7469                 if(this.hasClass(className)){
7470                     var re = this.classReCache[className];
7471                     if (!re) {
7472                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7473                        this.classReCache[className] = re;
7474                     }
7475                     this.dom.className =
7476                         this.dom.className.replace(re, " ");
7477                 }
7478             }
7479             return this;
7480         },
7481
7482         // private
7483         classReCache: {},
7484
7485         /**
7486          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7487          * @param {String} className The CSS class to toggle
7488          * @return {Roo.Element} this
7489          */
7490         toggleClass : function(className){
7491             if(this.hasClass(className)){
7492                 this.removeClass(className);
7493             }else{
7494                 this.addClass(className);
7495             }
7496             return this;
7497         },
7498
7499         /**
7500          * Checks if the specified CSS class exists on this element's DOM node.
7501          * @param {String} className The CSS class to check for
7502          * @return {Boolean} True if the class exists, else false
7503          */
7504         hasClass : function(className){
7505             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7506         },
7507
7508         /**
7509          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7510          * @param {String} oldClassName The CSS class to replace
7511          * @param {String} newClassName The replacement CSS class
7512          * @return {Roo.Element} this
7513          */
7514         replaceClass : function(oldClassName, newClassName){
7515             this.removeClass(oldClassName);
7516             this.addClass(newClassName);
7517             return this;
7518         },
7519
7520         /**
7521          * Returns an object with properties matching the styles requested.
7522          * For example, el.getStyles('color', 'font-size', 'width') might return
7523          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7524          * @param {String} style1 A style name
7525          * @param {String} style2 A style name
7526          * @param {String} etc.
7527          * @return {Object} The style object
7528          */
7529         getStyles : function(){
7530             var a = arguments, len = a.length, r = {};
7531             for(var i = 0; i < len; i++){
7532                 r[a[i]] = this.getStyle(a[i]);
7533             }
7534             return r;
7535         },
7536
7537         /**
7538          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7539          * @param {String} property The style property whose value is returned.
7540          * @return {String} The current value of the style property for this element.
7541          */
7542         getStyle : function(){
7543             return view && view.getComputedStyle ?
7544                 function(prop){
7545                     var el = this.dom, v, cs, camel;
7546                     if(prop == 'float'){
7547                         prop = "cssFloat";
7548                     }
7549                     if(el.style && (v = el.style[prop])){
7550                         return v;
7551                     }
7552                     if(cs = view.getComputedStyle(el, "")){
7553                         if(!(camel = propCache[prop])){
7554                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7555                         }
7556                         return cs[camel];
7557                     }
7558                     return null;
7559                 } :
7560                 function(prop){
7561                     var el = this.dom, v, cs, camel;
7562                     if(prop == 'opacity'){
7563                         if(typeof el.style.filter == 'string'){
7564                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7565                             if(m){
7566                                 var fv = parseFloat(m[1]);
7567                                 if(!isNaN(fv)){
7568                                     return fv ? fv / 100 : 0;
7569                                 }
7570                             }
7571                         }
7572                         return 1;
7573                     }else if(prop == 'float'){
7574                         prop = "styleFloat";
7575                     }
7576                     if(!(camel = propCache[prop])){
7577                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7578                     }
7579                     if(v = el.style[camel]){
7580                         return v;
7581                     }
7582                     if(cs = el.currentStyle){
7583                         return cs[camel];
7584                     }
7585                     return null;
7586                 };
7587         }(),
7588
7589         /**
7590          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7591          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7592          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7593          * @return {Roo.Element} this
7594          */
7595         setStyle : function(prop, value){
7596             if(typeof prop == "string"){
7597                 
7598                 if (prop == 'float') {
7599                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7600                     return this;
7601                 }
7602                 
7603                 var camel;
7604                 if(!(camel = propCache[prop])){
7605                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7606                 }
7607                 
7608                 if(camel == 'opacity') {
7609                     this.setOpacity(value);
7610                 }else{
7611                     this.dom.style[camel] = value;
7612                 }
7613             }else{
7614                 for(var style in prop){
7615                     if(typeof prop[style] != "function"){
7616                        this.setStyle(style, prop[style]);
7617                     }
7618                 }
7619             }
7620             return this;
7621         },
7622
7623         /**
7624          * More flexible version of {@link #setStyle} for setting style properties.
7625          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7626          * a function which returns such a specification.
7627          * @return {Roo.Element} this
7628          */
7629         applyStyles : function(style){
7630             Roo.DomHelper.applyStyles(this.dom, style);
7631             return this;
7632         },
7633
7634         /**
7635           * 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).
7636           * @return {Number} The X position of the element
7637           */
7638         getX : function(){
7639             return D.getX(this.dom);
7640         },
7641
7642         /**
7643           * 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).
7644           * @return {Number} The Y position of the element
7645           */
7646         getY : function(){
7647             return D.getY(this.dom);
7648         },
7649
7650         /**
7651           * 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).
7652           * @return {Array} The XY position of the element
7653           */
7654         getXY : function(){
7655             return D.getXY(this.dom);
7656         },
7657
7658         /**
7659          * 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).
7660          * @param {Number} The X position of the element
7661          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7662          * @return {Roo.Element} this
7663          */
7664         setX : function(x, animate){
7665             if(!animate || !A){
7666                 D.setX(this.dom, x);
7667             }else{
7668                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7669             }
7670             return this;
7671         },
7672
7673         /**
7674          * 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).
7675          * @param {Number} The Y position of the element
7676          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7677          * @return {Roo.Element} this
7678          */
7679         setY : function(y, animate){
7680             if(!animate || !A){
7681                 D.setY(this.dom, y);
7682             }else{
7683                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7684             }
7685             return this;
7686         },
7687
7688         /**
7689          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7690          * @param {String} left The left CSS property value
7691          * @return {Roo.Element} this
7692          */
7693         setLeft : function(left){
7694             this.setStyle("left", this.addUnits(left));
7695             return this;
7696         },
7697
7698         /**
7699          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7700          * @param {String} top The top CSS property value
7701          * @return {Roo.Element} this
7702          */
7703         setTop : function(top){
7704             this.setStyle("top", this.addUnits(top));
7705             return this;
7706         },
7707
7708         /**
7709          * Sets the element's CSS right style.
7710          * @param {String} right The right CSS property value
7711          * @return {Roo.Element} this
7712          */
7713         setRight : function(right){
7714             this.setStyle("right", this.addUnits(right));
7715             return this;
7716         },
7717
7718         /**
7719          * Sets the element's CSS bottom style.
7720          * @param {String} bottom The bottom CSS property value
7721          * @return {Roo.Element} this
7722          */
7723         setBottom : function(bottom){
7724             this.setStyle("bottom", this.addUnits(bottom));
7725             return this;
7726         },
7727
7728         /**
7729          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7730          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7731          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7732          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7733          * @return {Roo.Element} this
7734          */
7735         setXY : function(pos, animate){
7736             if(!animate || !A){
7737                 D.setXY(this.dom, pos);
7738             }else{
7739                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7740             }
7741             return this;
7742         },
7743
7744         /**
7745          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7746          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7747          * @param {Number} x X value for new position (coordinates are page-based)
7748          * @param {Number} y Y value for new position (coordinates are page-based)
7749          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7750          * @return {Roo.Element} this
7751          */
7752         setLocation : function(x, y, animate){
7753             this.setXY([x, y], this.preanim(arguments, 2));
7754             return this;
7755         },
7756
7757         /**
7758          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7759          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7760          * @param {Number} x X value for new position (coordinates are page-based)
7761          * @param {Number} y Y value for new position (coordinates are page-based)
7762          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7763          * @return {Roo.Element} this
7764          */
7765         moveTo : function(x, y, animate){
7766             this.setXY([x, y], this.preanim(arguments, 2));
7767             return this;
7768         },
7769
7770         /**
7771          * Returns the region of the given element.
7772          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7773          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7774          */
7775         getRegion : function(){
7776             return D.getRegion(this.dom);
7777         },
7778
7779         /**
7780          * Returns the offset height of the element
7781          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7782          * @return {Number} The element's height
7783          */
7784         getHeight : function(contentHeight){
7785             var h = this.dom.offsetHeight || 0;
7786             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7787         },
7788
7789         /**
7790          * Returns the offset width of the element
7791          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7792          * @return {Number} The element's width
7793          */
7794         getWidth : function(contentWidth){
7795             var w = this.dom.offsetWidth || 0;
7796             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7797         },
7798
7799         /**
7800          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7801          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7802          * if a height has not been set using CSS.
7803          * @return {Number}
7804          */
7805         getComputedHeight : function(){
7806             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7807             if(!h){
7808                 h = parseInt(this.getStyle('height'), 10) || 0;
7809                 if(!this.isBorderBox()){
7810                     h += this.getFrameWidth('tb');
7811                 }
7812             }
7813             return h;
7814         },
7815
7816         /**
7817          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7818          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7819          * if a width has not been set using CSS.
7820          * @return {Number}
7821          */
7822         getComputedWidth : function(){
7823             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7824             if(!w){
7825                 w = parseInt(this.getStyle('width'), 10) || 0;
7826                 if(!this.isBorderBox()){
7827                     w += this.getFrameWidth('lr');
7828                 }
7829             }
7830             return w;
7831         },
7832
7833         /**
7834          * Returns the size of the element.
7835          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7836          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7837          */
7838         getSize : function(contentSize){
7839             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7840         },
7841
7842         /**
7843          * Returns the width and height of the viewport.
7844          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7845          */
7846         getViewSize : function(){
7847             var d = this.dom, doc = document, aw = 0, ah = 0;
7848             if(d == doc || d == doc.body){
7849                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7850             }else{
7851                 return {
7852                     width : d.clientWidth,
7853                     height: d.clientHeight
7854                 };
7855             }
7856         },
7857
7858         /**
7859          * Returns the value of the "value" attribute
7860          * @param {Boolean} asNumber true to parse the value as a number
7861          * @return {String/Number}
7862          */
7863         getValue : function(asNumber){
7864             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7865         },
7866
7867         // private
7868         adjustWidth : function(width){
7869             if(typeof width == "number"){
7870                 if(this.autoBoxAdjust && !this.isBorderBox()){
7871                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7872                 }
7873                 if(width < 0){
7874                     width = 0;
7875                 }
7876             }
7877             return width;
7878         },
7879
7880         // private
7881         adjustHeight : function(height){
7882             if(typeof height == "number"){
7883                if(this.autoBoxAdjust && !this.isBorderBox()){
7884                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7885                }
7886                if(height < 0){
7887                    height = 0;
7888                }
7889             }
7890             return height;
7891         },
7892
7893         /**
7894          * Set the width of the element
7895          * @param {Number} width The new width
7896          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7897          * @return {Roo.Element} this
7898          */
7899         setWidth : function(width, animate){
7900             width = this.adjustWidth(width);
7901             if(!animate || !A){
7902                 this.dom.style.width = this.addUnits(width);
7903             }else{
7904                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7905             }
7906             return this;
7907         },
7908
7909         /**
7910          * Set the height of the element
7911          * @param {Number} height The new height
7912          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7913          * @return {Roo.Element} this
7914          */
7915          setHeight : function(height, animate){
7916             height = this.adjustHeight(height);
7917             if(!animate || !A){
7918                 this.dom.style.height = this.addUnits(height);
7919             }else{
7920                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7921             }
7922             return this;
7923         },
7924
7925         /**
7926          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7927          * @param {Number} width The new width
7928          * @param {Number} height The new height
7929          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7930          * @return {Roo.Element} this
7931          */
7932          setSize : function(width, height, animate){
7933             if(typeof width == "object"){ // in case of object from getSize()
7934                 height = width.height; width = width.width;
7935             }
7936             width = this.adjustWidth(width); height = this.adjustHeight(height);
7937             if(!animate || !A){
7938                 this.dom.style.width = this.addUnits(width);
7939                 this.dom.style.height = this.addUnits(height);
7940             }else{
7941                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7942             }
7943             return this;
7944         },
7945
7946         /**
7947          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7948          * @param {Number} x X value for new position (coordinates are page-based)
7949          * @param {Number} y Y value for new position (coordinates are page-based)
7950          * @param {Number} width The new width
7951          * @param {Number} height The new height
7952          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7953          * @return {Roo.Element} this
7954          */
7955         setBounds : function(x, y, width, height, animate){
7956             if(!animate || !A){
7957                 this.setSize(width, height);
7958                 this.setLocation(x, y);
7959             }else{
7960                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7961                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7962                               this.preanim(arguments, 4), 'motion');
7963             }
7964             return this;
7965         },
7966
7967         /**
7968          * 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.
7969          * @param {Roo.lib.Region} region The region to fill
7970          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7971          * @return {Roo.Element} this
7972          */
7973         setRegion : function(region, animate){
7974             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7975             return this;
7976         },
7977
7978         /**
7979          * Appends an event handler
7980          *
7981          * @param {String}   eventName     The type of event to append
7982          * @param {Function} fn        The method the event invokes
7983          * @param {Object} scope       (optional) The scope (this object) of the fn
7984          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7985          */
7986         addListener : function(eventName, fn, scope, options){
7987             if (this.dom) {
7988                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7989             }
7990         },
7991
7992         /**
7993          * Removes an event handler from this element
7994          * @param {String} eventName the type of event to remove
7995          * @param {Function} fn the method the event invokes
7996          * @return {Roo.Element} this
7997          */
7998         removeListener : function(eventName, fn){
7999             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8000             return this;
8001         },
8002
8003         /**
8004          * Removes all previous added listeners from this element
8005          * @return {Roo.Element} this
8006          */
8007         removeAllListeners : function(){
8008             E.purgeElement(this.dom);
8009             return this;
8010         },
8011
8012         relayEvent : function(eventName, observable){
8013             this.on(eventName, function(e){
8014                 observable.fireEvent(eventName, e);
8015             });
8016         },
8017
8018         /**
8019          * Set the opacity of the element
8020          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8021          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8022          * @return {Roo.Element} this
8023          */
8024          setOpacity : function(opacity, animate){
8025             if(!animate || !A){
8026                 var s = this.dom.style;
8027                 if(Roo.isIE){
8028                     s.zoom = 1;
8029                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8030                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8031                 }else{
8032                     s.opacity = opacity;
8033                 }
8034             }else{
8035                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8036             }
8037             return this;
8038         },
8039
8040         /**
8041          * Gets the left X coordinate
8042          * @param {Boolean} local True to get the local css position instead of page coordinate
8043          * @return {Number}
8044          */
8045         getLeft : function(local){
8046             if(!local){
8047                 return this.getX();
8048             }else{
8049                 return parseInt(this.getStyle("left"), 10) || 0;
8050             }
8051         },
8052
8053         /**
8054          * Gets the right X coordinate of the element (element X position + element width)
8055          * @param {Boolean} local True to get the local css position instead of page coordinate
8056          * @return {Number}
8057          */
8058         getRight : function(local){
8059             if(!local){
8060                 return this.getX() + this.getWidth();
8061             }else{
8062                 return (this.getLeft(true) + this.getWidth()) || 0;
8063             }
8064         },
8065
8066         /**
8067          * Gets the top Y coordinate
8068          * @param {Boolean} local True to get the local css position instead of page coordinate
8069          * @return {Number}
8070          */
8071         getTop : function(local) {
8072             if(!local){
8073                 return this.getY();
8074             }else{
8075                 return parseInt(this.getStyle("top"), 10) || 0;
8076             }
8077         },
8078
8079         /**
8080          * Gets the bottom Y coordinate of the element (element Y position + element height)
8081          * @param {Boolean} local True to get the local css position instead of page coordinate
8082          * @return {Number}
8083          */
8084         getBottom : function(local){
8085             if(!local){
8086                 return this.getY() + this.getHeight();
8087             }else{
8088                 return (this.getTop(true) + this.getHeight()) || 0;
8089             }
8090         },
8091
8092         /**
8093         * Initializes positioning on this element. If a desired position is not passed, it will make the
8094         * the element positioned relative IF it is not already positioned.
8095         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8096         * @param {Number} zIndex (optional) The zIndex to apply
8097         * @param {Number} x (optional) Set the page X position
8098         * @param {Number} y (optional) Set the page Y position
8099         */
8100         position : function(pos, zIndex, x, y){
8101             if(!pos){
8102                if(this.getStyle('position') == 'static'){
8103                    this.setStyle('position', 'relative');
8104                }
8105             }else{
8106                 this.setStyle("position", pos);
8107             }
8108             if(zIndex){
8109                 this.setStyle("z-index", zIndex);
8110             }
8111             if(x !== undefined && y !== undefined){
8112                 this.setXY([x, y]);
8113             }else if(x !== undefined){
8114                 this.setX(x);
8115             }else if(y !== undefined){
8116                 this.setY(y);
8117             }
8118         },
8119
8120         /**
8121         * Clear positioning back to the default when the document was loaded
8122         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8123         * @return {Roo.Element} this
8124          */
8125         clearPositioning : function(value){
8126             value = value ||'';
8127             this.setStyle({
8128                 "left": value,
8129                 "right": value,
8130                 "top": value,
8131                 "bottom": value,
8132                 "z-index": "",
8133                 "position" : "static"
8134             });
8135             return this;
8136         },
8137
8138         /**
8139         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8140         * snapshot before performing an update and then restoring the element.
8141         * @return {Object}
8142         */
8143         getPositioning : function(){
8144             var l = this.getStyle("left");
8145             var t = this.getStyle("top");
8146             return {
8147                 "position" : this.getStyle("position"),
8148                 "left" : l,
8149                 "right" : l ? "" : this.getStyle("right"),
8150                 "top" : t,
8151                 "bottom" : t ? "" : this.getStyle("bottom"),
8152                 "z-index" : this.getStyle("z-index")
8153             };
8154         },
8155
8156         /**
8157          * Gets the width of the border(s) for the specified side(s)
8158          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8159          * passing lr would get the border (l)eft width + the border (r)ight width.
8160          * @return {Number} The width of the sides passed added together
8161          */
8162         getBorderWidth : function(side){
8163             return this.addStyles(side, El.borders);
8164         },
8165
8166         /**
8167          * Gets the width of the padding(s) for the specified side(s)
8168          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8169          * passing lr would get the padding (l)eft + the padding (r)ight.
8170          * @return {Number} The padding of the sides passed added together
8171          */
8172         getPadding : function(side){
8173             return this.addStyles(side, El.paddings);
8174         },
8175
8176         /**
8177         * Set positioning with an object returned by getPositioning().
8178         * @param {Object} posCfg
8179         * @return {Roo.Element} this
8180          */
8181         setPositioning : function(pc){
8182             this.applyStyles(pc);
8183             if(pc.right == "auto"){
8184                 this.dom.style.right = "";
8185             }
8186             if(pc.bottom == "auto"){
8187                 this.dom.style.bottom = "";
8188             }
8189             return this;
8190         },
8191
8192         // private
8193         fixDisplay : function(){
8194             if(this.getStyle("display") == "none"){
8195                 this.setStyle("visibility", "hidden");
8196                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8197                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8198                     this.setStyle("display", "block");
8199                 }
8200             }
8201         },
8202
8203         /**
8204          * Quick set left and top adding default units
8205          * @param {String} left The left CSS property value
8206          * @param {String} top The top CSS property value
8207          * @return {Roo.Element} this
8208          */
8209          setLeftTop : function(left, top){
8210             this.dom.style.left = this.addUnits(left);
8211             this.dom.style.top = this.addUnits(top);
8212             return this;
8213         },
8214
8215         /**
8216          * Move this element relative to its current position.
8217          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8218          * @param {Number} distance How far to move the element in pixels
8219          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8220          * @return {Roo.Element} this
8221          */
8222          move : function(direction, distance, animate){
8223             var xy = this.getXY();
8224             direction = direction.toLowerCase();
8225             switch(direction){
8226                 case "l":
8227                 case "left":
8228                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8229                     break;
8230                case "r":
8231                case "right":
8232                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8233                     break;
8234                case "t":
8235                case "top":
8236                case "up":
8237                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8238                     break;
8239                case "b":
8240                case "bottom":
8241                case "down":
8242                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8243                     break;
8244             }
8245             return this;
8246         },
8247
8248         /**
8249          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8250          * @return {Roo.Element} this
8251          */
8252         clip : function(){
8253             if(!this.isClipped){
8254                this.isClipped = true;
8255                this.originalClip = {
8256                    "o": this.getStyle("overflow"),
8257                    "x": this.getStyle("overflow-x"),
8258                    "y": this.getStyle("overflow-y")
8259                };
8260                this.setStyle("overflow", "hidden");
8261                this.setStyle("overflow-x", "hidden");
8262                this.setStyle("overflow-y", "hidden");
8263             }
8264             return this;
8265         },
8266
8267         /**
8268          *  Return clipping (overflow) to original clipping before clip() was called
8269          * @return {Roo.Element} this
8270          */
8271         unclip : function(){
8272             if(this.isClipped){
8273                 this.isClipped = false;
8274                 var o = this.originalClip;
8275                 if(o.o){this.setStyle("overflow", o.o);}
8276                 if(o.x){this.setStyle("overflow-x", o.x);}
8277                 if(o.y){this.setStyle("overflow-y", o.y);}
8278             }
8279             return this;
8280         },
8281
8282
8283         /**
8284          * Gets the x,y coordinates specified by the anchor position on the element.
8285          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8286          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8287          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8288          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8289          * @return {Array} [x, y] An array containing the element's x and y coordinates
8290          */
8291         getAnchorXY : function(anchor, local, s){
8292             //Passing a different size is useful for pre-calculating anchors,
8293             //especially for anchored animations that change the el size.
8294
8295             var w, h, vp = false;
8296             if(!s){
8297                 var d = this.dom;
8298                 if(d == document.body || d == document){
8299                     vp = true;
8300                     w = D.getViewWidth(); h = D.getViewHeight();
8301                 }else{
8302                     w = this.getWidth(); h = this.getHeight();
8303                 }
8304             }else{
8305                 w = s.width;  h = s.height;
8306             }
8307             var x = 0, y = 0, r = Math.round;
8308             switch((anchor || "tl").toLowerCase()){
8309                 case "c":
8310                     x = r(w*.5);
8311                     y = r(h*.5);
8312                 break;
8313                 case "t":
8314                     x = r(w*.5);
8315                     y = 0;
8316                 break;
8317                 case "l":
8318                     x = 0;
8319                     y = r(h*.5);
8320                 break;
8321                 case "r":
8322                     x = w;
8323                     y = r(h*.5);
8324                 break;
8325                 case "b":
8326                     x = r(w*.5);
8327                     y = h;
8328                 break;
8329                 case "tl":
8330                     x = 0;
8331                     y = 0;
8332                 break;
8333                 case "bl":
8334                     x = 0;
8335                     y = h;
8336                 break;
8337                 case "br":
8338                     x = w;
8339                     y = h;
8340                 break;
8341                 case "tr":
8342                     x = w;
8343                     y = 0;
8344                 break;
8345             }
8346             if(local === true){
8347                 return [x, y];
8348             }
8349             if(vp){
8350                 var sc = this.getScroll();
8351                 return [x + sc.left, y + sc.top];
8352             }
8353             //Add the element's offset xy
8354             var o = this.getXY();
8355             return [x+o[0], y+o[1]];
8356         },
8357
8358         /**
8359          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8360          * supported position values.
8361          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8362          * @param {String} position The position to align to.
8363          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8364          * @return {Array} [x, y]
8365          */
8366         getAlignToXY : function(el, p, o){
8367             el = Roo.get(el);
8368             var d = this.dom;
8369             if(!el.dom){
8370                 throw "Element.alignTo with an element that doesn't exist";
8371             }
8372             var c = false; //constrain to viewport
8373             var p1 = "", p2 = "";
8374             o = o || [0,0];
8375
8376             if(!p){
8377                 p = "tl-bl";
8378             }else if(p == "?"){
8379                 p = "tl-bl?";
8380             }else if(p.indexOf("-") == -1){
8381                 p = "tl-" + p;
8382             }
8383             p = p.toLowerCase();
8384             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8385             if(!m){
8386                throw "Element.alignTo with an invalid alignment " + p;
8387             }
8388             p1 = m[1]; p2 = m[2]; c = !!m[3];
8389
8390             //Subtract the aligned el's internal xy from the target's offset xy
8391             //plus custom offset to get the aligned el's new offset xy
8392             var a1 = this.getAnchorXY(p1, true);
8393             var a2 = el.getAnchorXY(p2, false);
8394             var x = a2[0] - a1[0] + o[0];
8395             var y = a2[1] - a1[1] + o[1];
8396             if(c){
8397                 //constrain the aligned el to viewport if necessary
8398                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8399                 // 5px of margin for ie
8400                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8401
8402                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8403                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8404                 //otherwise swap the aligned el to the opposite border of the target.
8405                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8406                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8407                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8408                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8409
8410                var doc = document;
8411                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8412                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8413
8414                if((x+w) > dw + scrollX){
8415                     x = swapX ? r.left-w : dw+scrollX-w;
8416                 }
8417                if(x < scrollX){
8418                    x = swapX ? r.right : scrollX;
8419                }
8420                if((y+h) > dh + scrollY){
8421                     y = swapY ? r.top-h : dh+scrollY-h;
8422                 }
8423                if (y < scrollY){
8424                    y = swapY ? r.bottom : scrollY;
8425                }
8426             }
8427             return [x,y];
8428         },
8429
8430         // private
8431         getConstrainToXY : function(){
8432             var os = {top:0, left:0, bottom:0, right: 0};
8433
8434             return function(el, local, offsets, proposedXY){
8435                 el = Roo.get(el);
8436                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8437
8438                 var vw, vh, vx = 0, vy = 0;
8439                 if(el.dom == document.body || el.dom == document){
8440                     vw = Roo.lib.Dom.getViewWidth();
8441                     vh = Roo.lib.Dom.getViewHeight();
8442                 }else{
8443                     vw = el.dom.clientWidth;
8444                     vh = el.dom.clientHeight;
8445                     if(!local){
8446                         var vxy = el.getXY();
8447                         vx = vxy[0];
8448                         vy = vxy[1];
8449                     }
8450                 }
8451
8452                 var s = el.getScroll();
8453
8454                 vx += offsets.left + s.left;
8455                 vy += offsets.top + s.top;
8456
8457                 vw -= offsets.right;
8458                 vh -= offsets.bottom;
8459
8460                 var vr = vx+vw;
8461                 var vb = vy+vh;
8462
8463                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8464                 var x = xy[0], y = xy[1];
8465                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8466
8467                 // only move it if it needs it
8468                 var moved = false;
8469
8470                 // first validate right/bottom
8471                 if((x + w) > vr){
8472                     x = vr - w;
8473                     moved = true;
8474                 }
8475                 if((y + h) > vb){
8476                     y = vb - h;
8477                     moved = true;
8478                 }
8479                 // then make sure top/left isn't negative
8480                 if(x < vx){
8481                     x = vx;
8482                     moved = true;
8483                 }
8484                 if(y < vy){
8485                     y = vy;
8486                     moved = true;
8487                 }
8488                 return moved ? [x, y] : false;
8489             };
8490         }(),
8491
8492         // private
8493         adjustForConstraints : function(xy, parent, offsets){
8494             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8495         },
8496
8497         /**
8498          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8499          * document it aligns it to the viewport.
8500          * The position parameter is optional, and can be specified in any one of the following formats:
8501          * <ul>
8502          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8503          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8504          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8505          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8506          *   <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
8507          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8508          * </ul>
8509          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8510          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8511          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8512          * that specified in order to enforce the viewport constraints.
8513          * Following are all of the supported anchor positions:
8514     <pre>
8515     Value  Description
8516     -----  -----------------------------
8517     tl     The top left corner (default)
8518     t      The center of the top edge
8519     tr     The top right corner
8520     l      The center of the left edge
8521     c      In the center of the element
8522     r      The center of the right edge
8523     bl     The bottom left corner
8524     b      The center of the bottom edge
8525     br     The bottom right corner
8526     </pre>
8527     Example Usage:
8528     <pre><code>
8529     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8530     el.alignTo("other-el");
8531
8532     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8533     el.alignTo("other-el", "tr?");
8534
8535     // align the bottom right corner of el with the center left edge of other-el
8536     el.alignTo("other-el", "br-l?");
8537
8538     // align the center of el with the bottom left corner of other-el and
8539     // adjust the x position by -6 pixels (and the y position by 0)
8540     el.alignTo("other-el", "c-bl", [-6, 0]);
8541     </code></pre>
8542          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8543          * @param {String} position The position to align to.
8544          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8545          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8546          * @return {Roo.Element} this
8547          */
8548         alignTo : function(element, position, offsets, animate){
8549             var xy = this.getAlignToXY(element, position, offsets);
8550             this.setXY(xy, this.preanim(arguments, 3));
8551             return this;
8552         },
8553
8554         /**
8555          * Anchors an element to another element and realigns it when the window is resized.
8556          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8557          * @param {String} position The position to align to.
8558          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8559          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8560          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8561          * is a number, it is used as the buffer delay (defaults to 50ms).
8562          * @param {Function} callback The function to call after the animation finishes
8563          * @return {Roo.Element} this
8564          */
8565         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8566             var action = function(){
8567                 this.alignTo(el, alignment, offsets, animate);
8568                 Roo.callback(callback, this);
8569             };
8570             Roo.EventManager.onWindowResize(action, this);
8571             var tm = typeof monitorScroll;
8572             if(tm != 'undefined'){
8573                 Roo.EventManager.on(window, 'scroll', action, this,
8574                     {buffer: tm == 'number' ? monitorScroll : 50});
8575             }
8576             action.call(this); // align immediately
8577             return this;
8578         },
8579         /**
8580          * Clears any opacity settings from this element. Required in some cases for IE.
8581          * @return {Roo.Element} this
8582          */
8583         clearOpacity : function(){
8584             if (window.ActiveXObject) {
8585                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8586                     this.dom.style.filter = "";
8587                 }
8588             } else {
8589                 this.dom.style.opacity = "";
8590                 this.dom.style["-moz-opacity"] = "";
8591                 this.dom.style["-khtml-opacity"] = "";
8592             }
8593             return this;
8594         },
8595
8596         /**
8597          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8598          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8599          * @return {Roo.Element} this
8600          */
8601         hide : function(animate){
8602             this.setVisible(false, this.preanim(arguments, 0));
8603             return this;
8604         },
8605
8606         /**
8607         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8608         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8609          * @return {Roo.Element} this
8610          */
8611         show : function(animate){
8612             this.setVisible(true, this.preanim(arguments, 0));
8613             return this;
8614         },
8615
8616         /**
8617          * @private Test if size has a unit, otherwise appends the default
8618          */
8619         addUnits : function(size){
8620             return Roo.Element.addUnits(size, this.defaultUnit);
8621         },
8622
8623         /**
8624          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8625          * @return {Roo.Element} this
8626          */
8627         beginMeasure : function(){
8628             var el = this.dom;
8629             if(el.offsetWidth || el.offsetHeight){
8630                 return this; // offsets work already
8631             }
8632             var changed = [];
8633             var p = this.dom, b = document.body; // start with this element
8634             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8635                 var pe = Roo.get(p);
8636                 if(pe.getStyle('display') == 'none'){
8637                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8638                     p.style.visibility = "hidden";
8639                     p.style.display = "block";
8640                 }
8641                 p = p.parentNode;
8642             }
8643             this._measureChanged = changed;
8644             return this;
8645
8646         },
8647
8648         /**
8649          * Restores displays to before beginMeasure was called
8650          * @return {Roo.Element} this
8651          */
8652         endMeasure : function(){
8653             var changed = this._measureChanged;
8654             if(changed){
8655                 for(var i = 0, len = changed.length; i < len; i++) {
8656                     var r = changed[i];
8657                     r.el.style.visibility = r.visibility;
8658                     r.el.style.display = "none";
8659                 }
8660                 this._measureChanged = null;
8661             }
8662             return this;
8663         },
8664
8665         /**
8666         * Update the innerHTML of this element, optionally searching for and processing scripts
8667         * @param {String} html The new HTML
8668         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8669         * @param {Function} callback For async script loading you can be noticed when the update completes
8670         * @return {Roo.Element} this
8671          */
8672         update : function(html, loadScripts, callback){
8673             if(typeof html == "undefined"){
8674                 html = "";
8675             }
8676             if(loadScripts !== true){
8677                 this.dom.innerHTML = html;
8678                 if(typeof callback == "function"){
8679                     callback();
8680                 }
8681                 return this;
8682             }
8683             var id = Roo.id();
8684             var dom = this.dom;
8685
8686             html += '<span id="' + id + '"></span>';
8687
8688             E.onAvailable(id, function(){
8689                 var hd = document.getElementsByTagName("head")[0];
8690                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8691                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8692                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8693
8694                 var match;
8695                 while(match = re.exec(html)){
8696                     var attrs = match[1];
8697                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8698                     if(srcMatch && srcMatch[2]){
8699                        var s = document.createElement("script");
8700                        s.src = srcMatch[2];
8701                        var typeMatch = attrs.match(typeRe);
8702                        if(typeMatch && typeMatch[2]){
8703                            s.type = typeMatch[2];
8704                        }
8705                        hd.appendChild(s);
8706                     }else if(match[2] && match[2].length > 0){
8707                         if(window.execScript) {
8708                            window.execScript(match[2]);
8709                         } else {
8710                             /**
8711                              * eval:var:id
8712                              * eval:var:dom
8713                              * eval:var:html
8714                              * 
8715                              */
8716                            window.eval(match[2]);
8717                         }
8718                     }
8719                 }
8720                 var el = document.getElementById(id);
8721                 if(el){el.parentNode.removeChild(el);}
8722                 if(typeof callback == "function"){
8723                     callback();
8724                 }
8725             });
8726             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8727             return this;
8728         },
8729
8730         /**
8731          * Direct access to the UpdateManager update() method (takes the same parameters).
8732          * @param {String/Function} url The url for this request or a function to call to get the url
8733          * @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}
8734          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8735          * @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.
8736          * @return {Roo.Element} this
8737          */
8738         load : function(){
8739             var um = this.getUpdateManager();
8740             um.update.apply(um, arguments);
8741             return this;
8742         },
8743
8744         /**
8745         * Gets this element's UpdateManager
8746         * @return {Roo.UpdateManager} The UpdateManager
8747         */
8748         getUpdateManager : function(){
8749             if(!this.updateManager){
8750                 this.updateManager = new Roo.UpdateManager(this);
8751             }
8752             return this.updateManager;
8753         },
8754
8755         /**
8756          * Disables text selection for this element (normalized across browsers)
8757          * @return {Roo.Element} this
8758          */
8759         unselectable : function(){
8760             this.dom.unselectable = "on";
8761             this.swallowEvent("selectstart", true);
8762             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8763             this.addClass("x-unselectable");
8764             return this;
8765         },
8766
8767         /**
8768         * Calculates the x, y to center this element on the screen
8769         * @return {Array} The x, y values [x, y]
8770         */
8771         getCenterXY : function(){
8772             return this.getAlignToXY(document, 'c-c');
8773         },
8774
8775         /**
8776         * Centers the Element in either the viewport, or another Element.
8777         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8778         */
8779         center : function(centerIn){
8780             this.alignTo(centerIn || document, 'c-c');
8781             return this;
8782         },
8783
8784         /**
8785          * Tests various css rules/browsers to determine if this element uses a border box
8786          * @return {Boolean}
8787          */
8788         isBorderBox : function(){
8789             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8790         },
8791
8792         /**
8793          * Return a box {x, y, width, height} that can be used to set another elements
8794          * size/location to match this element.
8795          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8796          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8797          * @return {Object} box An object in the format {x, y, width, height}
8798          */
8799         getBox : function(contentBox, local){
8800             var xy;
8801             if(!local){
8802                 xy = this.getXY();
8803             }else{
8804                 var left = parseInt(this.getStyle("left"), 10) || 0;
8805                 var top = parseInt(this.getStyle("top"), 10) || 0;
8806                 xy = [left, top];
8807             }
8808             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8809             if(!contentBox){
8810                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8811             }else{
8812                 var l = this.getBorderWidth("l")+this.getPadding("l");
8813                 var r = this.getBorderWidth("r")+this.getPadding("r");
8814                 var t = this.getBorderWidth("t")+this.getPadding("t");
8815                 var b = this.getBorderWidth("b")+this.getPadding("b");
8816                 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)};
8817             }
8818             bx.right = bx.x + bx.width;
8819             bx.bottom = bx.y + bx.height;
8820             return bx;
8821         },
8822
8823         /**
8824          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8825          for more information about the sides.
8826          * @param {String} sides
8827          * @return {Number}
8828          */
8829         getFrameWidth : function(sides, onlyContentBox){
8830             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8831         },
8832
8833         /**
8834          * 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.
8835          * @param {Object} box The box to fill {x, y, width, height}
8836          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8837          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8838          * @return {Roo.Element} this
8839          */
8840         setBox : function(box, adjust, animate){
8841             var w = box.width, h = box.height;
8842             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8843                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8844                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8845             }
8846             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8847             return this;
8848         },
8849
8850         /**
8851          * Forces the browser to repaint this element
8852          * @return {Roo.Element} this
8853          */
8854          repaint : function(){
8855             var dom = this.dom;
8856             this.addClass("x-repaint");
8857             setTimeout(function(){
8858                 Roo.get(dom).removeClass("x-repaint");
8859             }, 1);
8860             return this;
8861         },
8862
8863         /**
8864          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8865          * then it returns the calculated width of the sides (see getPadding)
8866          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8867          * @return {Object/Number}
8868          */
8869         getMargins : function(side){
8870             if(!side){
8871                 return {
8872                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8873                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8874                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8875                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8876                 };
8877             }else{
8878                 return this.addStyles(side, El.margins);
8879              }
8880         },
8881
8882         // private
8883         addStyles : function(sides, styles){
8884             var val = 0, v, w;
8885             for(var i = 0, len = sides.length; i < len; i++){
8886                 v = this.getStyle(styles[sides.charAt(i)]);
8887                 if(v){
8888                      w = parseInt(v, 10);
8889                      if(w){ val += w; }
8890                 }
8891             }
8892             return val;
8893         },
8894
8895         /**
8896          * Creates a proxy element of this element
8897          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8898          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8899          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8900          * @return {Roo.Element} The new proxy element
8901          */
8902         createProxy : function(config, renderTo, matchBox){
8903             if(renderTo){
8904                 renderTo = Roo.getDom(renderTo);
8905             }else{
8906                 renderTo = document.body;
8907             }
8908             config = typeof config == "object" ?
8909                 config : {tag : "div", cls: config};
8910             var proxy = Roo.DomHelper.append(renderTo, config, true);
8911             if(matchBox){
8912                proxy.setBox(this.getBox());
8913             }
8914             return proxy;
8915         },
8916
8917         /**
8918          * Puts a mask over this element to disable user interaction. Requires core.css.
8919          * This method can only be applied to elements which accept child nodes.
8920          * @param {String} msg (optional) A message to display in the mask
8921          * @param {String} msgCls (optional) A css class to apply to the msg element
8922          * @return {Element} The mask  element
8923          */
8924         mask : function(msg, msgCls)
8925         {
8926             if(this.getStyle("position") == "static"){
8927                 this.setStyle("position", "relative");
8928             }
8929             if(!this._mask){
8930                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8931             }
8932             this.addClass("x-masked");
8933             this._mask.setDisplayed(true);
8934             
8935             // we wander
8936             var z = 0;
8937             var dom = this.dom
8938             while (dom && dom.style) {
8939                 if (!isNaN(parseInt(dom.style.zIndex))) {
8940                     z = Math.max(z, parseInt(dom.style.zIndex));
8941                 }
8942                 dom = dom.parentNode;
8943             }
8944             // if we are masking the body - then it hides everything..
8945             if (this.dom == document.body) {
8946                 z = 1000000;
8947                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8948                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8949             }
8950            
8951             if(typeof msg == 'string'){
8952                 if(!this._maskMsg){
8953                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8954                 }
8955                 var mm = this._maskMsg;
8956                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8957                 mm.dom.firstChild.innerHTML = msg;
8958                 mm.setDisplayed(true);
8959                 mm.center(this);
8960                 mm.setStyle('z-index', z + 102);
8961             }
8962             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8963                 this._mask.setHeight(this.getHeight());
8964             }
8965             this._mask.setStyle('z-index', z + 100);
8966             
8967             return this._mask;
8968         },
8969
8970         /**
8971          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8972          * it is cached for reuse.
8973          */
8974         unmask : function(removeEl){
8975             if(this._mask){
8976                 if(removeEl === true){
8977                     this._mask.remove();
8978                     delete this._mask;
8979                     if(this._maskMsg){
8980                         this._maskMsg.remove();
8981                         delete this._maskMsg;
8982                     }
8983                 }else{
8984                     this._mask.setDisplayed(false);
8985                     if(this._maskMsg){
8986                         this._maskMsg.setDisplayed(false);
8987                     }
8988                 }
8989             }
8990             this.removeClass("x-masked");
8991         },
8992
8993         /**
8994          * Returns true if this element is masked
8995          * @return {Boolean}
8996          */
8997         isMasked : function(){
8998             return this._mask && this._mask.isVisible();
8999         },
9000
9001         /**
9002          * Creates an iframe shim for this element to keep selects and other windowed objects from
9003          * showing through.
9004          * @return {Roo.Element} The new shim element
9005          */
9006         createShim : function(){
9007             var el = document.createElement('iframe');
9008             el.frameBorder = 'no';
9009             el.className = 'roo-shim';
9010             if(Roo.isIE && Roo.isSecure){
9011                 el.src = Roo.SSL_SECURE_URL;
9012             }
9013             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9014             shim.autoBoxAdjust = false;
9015             return shim;
9016         },
9017
9018         /**
9019          * Removes this element from the DOM and deletes it from the cache
9020          */
9021         remove : function(){
9022             if(this.dom.parentNode){
9023                 this.dom.parentNode.removeChild(this.dom);
9024             }
9025             delete El.cache[this.dom.id];
9026         },
9027
9028         /**
9029          * Sets up event handlers to add and remove a css class when the mouse is over this element
9030          * @param {String} className
9031          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9032          * mouseout events for children elements
9033          * @return {Roo.Element} this
9034          */
9035         addClassOnOver : function(className, preventFlicker){
9036             this.on("mouseover", function(){
9037                 Roo.fly(this, '_internal').addClass(className);
9038             }, this.dom);
9039             var removeFn = function(e){
9040                 if(preventFlicker !== true || !e.within(this, true)){
9041                     Roo.fly(this, '_internal').removeClass(className);
9042                 }
9043             };
9044             this.on("mouseout", removeFn, this.dom);
9045             return this;
9046         },
9047
9048         /**
9049          * Sets up event handlers to add and remove a css class when this element has the focus
9050          * @param {String} className
9051          * @return {Roo.Element} this
9052          */
9053         addClassOnFocus : function(className){
9054             this.on("focus", function(){
9055                 Roo.fly(this, '_internal').addClass(className);
9056             }, this.dom);
9057             this.on("blur", function(){
9058                 Roo.fly(this, '_internal').removeClass(className);
9059             }, this.dom);
9060             return this;
9061         },
9062         /**
9063          * 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)
9064          * @param {String} className
9065          * @return {Roo.Element} this
9066          */
9067         addClassOnClick : function(className){
9068             var dom = this.dom;
9069             this.on("mousedown", function(){
9070                 Roo.fly(dom, '_internal').addClass(className);
9071                 var d = Roo.get(document);
9072                 var fn = function(){
9073                     Roo.fly(dom, '_internal').removeClass(className);
9074                     d.removeListener("mouseup", fn);
9075                 };
9076                 d.on("mouseup", fn);
9077             });
9078             return this;
9079         },
9080
9081         /**
9082          * Stops the specified event from bubbling and optionally prevents the default action
9083          * @param {String} eventName
9084          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9085          * @return {Roo.Element} this
9086          */
9087         swallowEvent : function(eventName, preventDefault){
9088             var fn = function(e){
9089                 e.stopPropagation();
9090                 if(preventDefault){
9091                     e.preventDefault();
9092                 }
9093             };
9094             if(eventName instanceof Array){
9095                 for(var i = 0, len = eventName.length; i < len; i++){
9096                      this.on(eventName[i], fn);
9097                 }
9098                 return this;
9099             }
9100             this.on(eventName, fn);
9101             return this;
9102         },
9103
9104         /**
9105          * @private
9106          */
9107       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9108
9109         /**
9110          * Sizes this element to its parent element's dimensions performing
9111          * neccessary box adjustments.
9112          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9113          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9114          * @return {Roo.Element} this
9115          */
9116         fitToParent : function(monitorResize, targetParent) {
9117           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9118           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9119           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9120             return;
9121           }
9122           var p = Roo.get(targetParent || this.dom.parentNode);
9123           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9124           if (monitorResize === true) {
9125             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9126             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9127           }
9128           return this;
9129         },
9130
9131         /**
9132          * Gets the next sibling, skipping text nodes
9133          * @return {HTMLElement} The next sibling or null
9134          */
9135         getNextSibling : function(){
9136             var n = this.dom.nextSibling;
9137             while(n && n.nodeType != 1){
9138                 n = n.nextSibling;
9139             }
9140             return n;
9141         },
9142
9143         /**
9144          * Gets the previous sibling, skipping text nodes
9145          * @return {HTMLElement} The previous sibling or null
9146          */
9147         getPrevSibling : function(){
9148             var n = this.dom.previousSibling;
9149             while(n && n.nodeType != 1){
9150                 n = n.previousSibling;
9151             }
9152             return n;
9153         },
9154
9155
9156         /**
9157          * Appends the passed element(s) to this element
9158          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9159          * @return {Roo.Element} this
9160          */
9161         appendChild: function(el){
9162             el = Roo.get(el);
9163             el.appendTo(this);
9164             return this;
9165         },
9166
9167         /**
9168          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9169          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9170          * automatically generated with the specified attributes.
9171          * @param {HTMLElement} insertBefore (optional) a child element of this element
9172          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9173          * @return {Roo.Element} The new child element
9174          */
9175         createChild: function(config, insertBefore, returnDom){
9176             config = config || {tag:'div'};
9177             if(insertBefore){
9178                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9179             }
9180             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9181         },
9182
9183         /**
9184          * Appends this element to the passed element
9185          * @param {String/HTMLElement/Element} el The new parent element
9186          * @return {Roo.Element} this
9187          */
9188         appendTo: function(el){
9189             el = Roo.getDom(el);
9190             el.appendChild(this.dom);
9191             return this;
9192         },
9193
9194         /**
9195          * Inserts this element before the passed element in the DOM
9196          * @param {String/HTMLElement/Element} el The element to insert before
9197          * @return {Roo.Element} this
9198          */
9199         insertBefore: function(el){
9200             el = Roo.getDom(el);
9201             el.parentNode.insertBefore(this.dom, el);
9202             return this;
9203         },
9204
9205         /**
9206          * Inserts this element after the passed element in the DOM
9207          * @param {String/HTMLElement/Element} el The element to insert after
9208          * @return {Roo.Element} this
9209          */
9210         insertAfter: function(el){
9211             el = Roo.getDom(el);
9212             el.parentNode.insertBefore(this.dom, el.nextSibling);
9213             return this;
9214         },
9215
9216         /**
9217          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9218          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9219          * @return {Roo.Element} The new child
9220          */
9221         insertFirst: function(el, returnDom){
9222             el = el || {};
9223             if(typeof el == 'object' && !el.nodeType){ // dh config
9224                 return this.createChild(el, this.dom.firstChild, returnDom);
9225             }else{
9226                 el = Roo.getDom(el);
9227                 this.dom.insertBefore(el, this.dom.firstChild);
9228                 return !returnDom ? Roo.get(el) : el;
9229             }
9230         },
9231
9232         /**
9233          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9234          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9235          * @param {String} where (optional) 'before' or 'after' defaults to before
9236          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9237          * @return {Roo.Element} the inserted Element
9238          */
9239         insertSibling: function(el, where, returnDom){
9240             where = where ? where.toLowerCase() : 'before';
9241             el = el || {};
9242             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9243
9244             if(typeof el == 'object' && !el.nodeType){ // dh config
9245                 if(where == 'after' && !this.dom.nextSibling){
9246                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9247                 }else{
9248                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9249                 }
9250
9251             }else{
9252                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9253                             where == 'before' ? this.dom : this.dom.nextSibling);
9254                 if(!returnDom){
9255                     rt = Roo.get(rt);
9256                 }
9257             }
9258             return rt;
9259         },
9260
9261         /**
9262          * Creates and wraps this element with another element
9263          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9264          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9265          * @return {HTMLElement/Element} The newly created wrapper element
9266          */
9267         wrap: function(config, returnDom){
9268             if(!config){
9269                 config = {tag: "div"};
9270             }
9271             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9272             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9273             return newEl;
9274         },
9275
9276         /**
9277          * Replaces the passed element with this element
9278          * @param {String/HTMLElement/Element} el The element to replace
9279          * @return {Roo.Element} this
9280          */
9281         replace: function(el){
9282             el = Roo.get(el);
9283             this.insertBefore(el);
9284             el.remove();
9285             return this;
9286         },
9287
9288         /**
9289          * Inserts an html fragment into this element
9290          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9291          * @param {String} html The HTML fragment
9292          * @param {Boolean} returnEl True to return an Roo.Element
9293          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9294          */
9295         insertHtml : function(where, html, returnEl){
9296             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9297             return returnEl ? Roo.get(el) : el;
9298         },
9299
9300         /**
9301          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9302          * @param {Object} o The object with the attributes
9303          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9304          * @return {Roo.Element} this
9305          */
9306         set : function(o, useSet){
9307             var el = this.dom;
9308             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9309             for(var attr in o){
9310                 if(attr == "style" || typeof o[attr] == "function") continue;
9311                 if(attr=="cls"){
9312                     el.className = o["cls"];
9313                 }else{
9314                     if(useSet) el.setAttribute(attr, o[attr]);
9315                     else el[attr] = o[attr];
9316                 }
9317             }
9318             if(o.style){
9319                 Roo.DomHelper.applyStyles(el, o.style);
9320             }
9321             return this;
9322         },
9323
9324         /**
9325          * Convenience method for constructing a KeyMap
9326          * @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:
9327          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9328          * @param {Function} fn The function to call
9329          * @param {Object} scope (optional) The scope of the function
9330          * @return {Roo.KeyMap} The KeyMap created
9331          */
9332         addKeyListener : function(key, fn, scope){
9333             var config;
9334             if(typeof key != "object" || key instanceof Array){
9335                 config = {
9336                     key: key,
9337                     fn: fn,
9338                     scope: scope
9339                 };
9340             }else{
9341                 config = {
9342                     key : key.key,
9343                     shift : key.shift,
9344                     ctrl : key.ctrl,
9345                     alt : key.alt,
9346                     fn: fn,
9347                     scope: scope
9348                 };
9349             }
9350             return new Roo.KeyMap(this, config);
9351         },
9352
9353         /**
9354          * Creates a KeyMap for this element
9355          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9356          * @return {Roo.KeyMap} The KeyMap created
9357          */
9358         addKeyMap : function(config){
9359             return new Roo.KeyMap(this, config);
9360         },
9361
9362         /**
9363          * Returns true if this element is scrollable.
9364          * @return {Boolean}
9365          */
9366          isScrollable : function(){
9367             var dom = this.dom;
9368             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9369         },
9370
9371         /**
9372          * 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().
9373          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9374          * @param {Number} value The new scroll value
9375          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9376          * @return {Element} this
9377          */
9378
9379         scrollTo : function(side, value, animate){
9380             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9381             if(!animate || !A){
9382                 this.dom[prop] = value;
9383             }else{
9384                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9385                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9386             }
9387             return this;
9388         },
9389
9390         /**
9391          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9392          * within this element's scrollable range.
9393          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9394          * @param {Number} distance How far to scroll the element in pixels
9395          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9396          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9397          * was scrolled as far as it could go.
9398          */
9399          scroll : function(direction, distance, animate){
9400              if(!this.isScrollable()){
9401                  return;
9402              }
9403              var el = this.dom;
9404              var l = el.scrollLeft, t = el.scrollTop;
9405              var w = el.scrollWidth, h = el.scrollHeight;
9406              var cw = el.clientWidth, ch = el.clientHeight;
9407              direction = direction.toLowerCase();
9408              var scrolled = false;
9409              var a = this.preanim(arguments, 2);
9410              switch(direction){
9411                  case "l":
9412                  case "left":
9413                      if(w - l > cw){
9414                          var v = Math.min(l + distance, w-cw);
9415                          this.scrollTo("left", v, a);
9416                          scrolled = true;
9417                      }
9418                      break;
9419                 case "r":
9420                 case "right":
9421                      if(l > 0){
9422                          var v = Math.max(l - distance, 0);
9423                          this.scrollTo("left", v, a);
9424                          scrolled = true;
9425                      }
9426                      break;
9427                 case "t":
9428                 case "top":
9429                 case "up":
9430                      if(t > 0){
9431                          var v = Math.max(t - distance, 0);
9432                          this.scrollTo("top", v, a);
9433                          scrolled = true;
9434                      }
9435                      break;
9436                 case "b":
9437                 case "bottom":
9438                 case "down":
9439                      if(h - t > ch){
9440                          var v = Math.min(t + distance, h-ch);
9441                          this.scrollTo("top", v, a);
9442                          scrolled = true;
9443                      }
9444                      break;
9445              }
9446              return scrolled;
9447         },
9448
9449         /**
9450          * Translates the passed page coordinates into left/top css values for this element
9451          * @param {Number/Array} x The page x or an array containing [x, y]
9452          * @param {Number} y The page y
9453          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9454          */
9455         translatePoints : function(x, y){
9456             if(typeof x == 'object' || x instanceof Array){
9457                 y = x[1]; x = x[0];
9458             }
9459             var p = this.getStyle('position');
9460             var o = this.getXY();
9461
9462             var l = parseInt(this.getStyle('left'), 10);
9463             var t = parseInt(this.getStyle('top'), 10);
9464
9465             if(isNaN(l)){
9466                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9467             }
9468             if(isNaN(t)){
9469                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9470             }
9471
9472             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9473         },
9474
9475         /**
9476          * Returns the current scroll position of the element.
9477          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9478          */
9479         getScroll : function(){
9480             var d = this.dom, doc = document;
9481             if(d == doc || d == doc.body){
9482                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9483                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9484                 return {left: l, top: t};
9485             }else{
9486                 return {left: d.scrollLeft, top: d.scrollTop};
9487             }
9488         },
9489
9490         /**
9491          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9492          * are convert to standard 6 digit hex color.
9493          * @param {String} attr The css attribute
9494          * @param {String} defaultValue The default value to use when a valid color isn't found
9495          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9496          * YUI color anims.
9497          */
9498         getColor : function(attr, defaultValue, prefix){
9499             var v = this.getStyle(attr);
9500             if(!v || v == "transparent" || v == "inherit") {
9501                 return defaultValue;
9502             }
9503             var color = typeof prefix == "undefined" ? "#" : prefix;
9504             if(v.substr(0, 4) == "rgb("){
9505                 var rvs = v.slice(4, v.length -1).split(",");
9506                 for(var i = 0; i < 3; i++){
9507                     var h = parseInt(rvs[i]).toString(16);
9508                     if(h < 16){
9509                         h = "0" + h;
9510                     }
9511                     color += h;
9512                 }
9513             } else {
9514                 if(v.substr(0, 1) == "#"){
9515                     if(v.length == 4) {
9516                         for(var i = 1; i < 4; i++){
9517                             var c = v.charAt(i);
9518                             color +=  c + c;
9519                         }
9520                     }else if(v.length == 7){
9521                         color += v.substr(1);
9522                     }
9523                 }
9524             }
9525             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9526         },
9527
9528         /**
9529          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9530          * gradient background, rounded corners and a 4-way shadow.
9531          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9532          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9533          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9534          * @return {Roo.Element} this
9535          */
9536         boxWrap : function(cls){
9537             cls = cls || 'x-box';
9538             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9539             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9540             return el;
9541         },
9542
9543         /**
9544          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9545          * @param {String} namespace The namespace in which to look for the attribute
9546          * @param {String} name The attribute name
9547          * @return {String} The attribute value
9548          */
9549         getAttributeNS : Roo.isIE ? function(ns, name){
9550             var d = this.dom;
9551             var type = typeof d[ns+":"+name];
9552             if(type != 'undefined' && type != 'unknown'){
9553                 return d[ns+":"+name];
9554             }
9555             return d[name];
9556         } : function(ns, name){
9557             var d = this.dom;
9558             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9559         },
9560         
9561         
9562         /**
9563          * Sets or Returns the value the dom attribute value
9564          * @param {String} name The attribute name
9565          * @param {String} value (optional) The value to set the attribute to
9566          * @return {String} The attribute value
9567          */
9568         attr : function(name){
9569             if (arguments.length > 1) {
9570                 this.dom.setAttribute(name, arguments[1]);
9571                 return arguments[1];
9572             }
9573             if (!this.dom.hasAttribute(name)) {
9574                 return undefined;
9575             }
9576             return this.dom.getAttribute(name);
9577         }
9578         
9579         
9580         
9581     };
9582
9583     var ep = El.prototype;
9584
9585     /**
9586      * Appends an event handler (Shorthand for addListener)
9587      * @param {String}   eventName     The type of event to append
9588      * @param {Function} fn        The method the event invokes
9589      * @param {Object} scope       (optional) The scope (this object) of the fn
9590      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9591      * @method
9592      */
9593     ep.on = ep.addListener;
9594         // backwards compat
9595     ep.mon = ep.addListener;
9596
9597     /**
9598      * Removes an event handler from this element (shorthand for removeListener)
9599      * @param {String} eventName the type of event to remove
9600      * @param {Function} fn the method the event invokes
9601      * @return {Roo.Element} this
9602      * @method
9603      */
9604     ep.un = ep.removeListener;
9605
9606     /**
9607      * true to automatically adjust width and height settings for box-model issues (default to true)
9608      */
9609     ep.autoBoxAdjust = true;
9610
9611     // private
9612     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9613
9614     // private
9615     El.addUnits = function(v, defaultUnit){
9616         if(v === "" || v == "auto"){
9617             return v;
9618         }
9619         if(v === undefined){
9620             return '';
9621         }
9622         if(typeof v == "number" || !El.unitPattern.test(v)){
9623             return v + (defaultUnit || 'px');
9624         }
9625         return v;
9626     };
9627
9628     // special markup used throughout Roo when box wrapping elements
9629     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>';
9630     /**
9631      * Visibility mode constant - Use visibility to hide element
9632      * @static
9633      * @type Number
9634      */
9635     El.VISIBILITY = 1;
9636     /**
9637      * Visibility mode constant - Use display to hide element
9638      * @static
9639      * @type Number
9640      */
9641     El.DISPLAY = 2;
9642
9643     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9644     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9645     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9646
9647
9648
9649     /**
9650      * @private
9651      */
9652     El.cache = {};
9653
9654     var docEl;
9655
9656     /**
9657      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9658      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9659      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9660      * @return {Element} The Element object
9661      * @static
9662      */
9663     El.get = function(el){
9664         var ex, elm, id;
9665         if(!el){ return null; }
9666         if(typeof el == "string"){ // element id
9667             if(!(elm = document.getElementById(el))){
9668                 return null;
9669             }
9670             if(ex = El.cache[el]){
9671                 ex.dom = elm;
9672             }else{
9673                 ex = El.cache[el] = new El(elm);
9674             }
9675             return ex;
9676         }else if(el.tagName){ // dom element
9677             if(!(id = el.id)){
9678                 id = Roo.id(el);
9679             }
9680             if(ex = El.cache[id]){
9681                 ex.dom = el;
9682             }else{
9683                 ex = El.cache[id] = new El(el);
9684             }
9685             return ex;
9686         }else if(el instanceof El){
9687             if(el != docEl){
9688                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9689                                                               // catch case where it hasn't been appended
9690                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9691             }
9692             return el;
9693         }else if(el.isComposite){
9694             return el;
9695         }else if(el instanceof Array){
9696             return El.select(el);
9697         }else if(el == document){
9698             // create a bogus element object representing the document object
9699             if(!docEl){
9700                 var f = function(){};
9701                 f.prototype = El.prototype;
9702                 docEl = new f();
9703                 docEl.dom = document;
9704             }
9705             return docEl;
9706         }
9707         return null;
9708     };
9709
9710     // private
9711     El.uncache = function(el){
9712         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9713             if(a[i]){
9714                 delete El.cache[a[i].id || a[i]];
9715             }
9716         }
9717     };
9718
9719     // private
9720     // Garbage collection - uncache elements/purge listeners on orphaned elements
9721     // so we don't hold a reference and cause the browser to retain them
9722     El.garbageCollect = function(){
9723         if(!Roo.enableGarbageCollector){
9724             clearInterval(El.collectorThread);
9725             return;
9726         }
9727         for(var eid in El.cache){
9728             var el = El.cache[eid], d = el.dom;
9729             // -------------------------------------------------------
9730             // Determining what is garbage:
9731             // -------------------------------------------------------
9732             // !d
9733             // dom node is null, definitely garbage
9734             // -------------------------------------------------------
9735             // !d.parentNode
9736             // no parentNode == direct orphan, definitely garbage
9737             // -------------------------------------------------------
9738             // !d.offsetParent && !document.getElementById(eid)
9739             // display none elements have no offsetParent so we will
9740             // also try to look it up by it's id. However, check
9741             // offsetParent first so we don't do unneeded lookups.
9742             // This enables collection of elements that are not orphans
9743             // directly, but somewhere up the line they have an orphan
9744             // parent.
9745             // -------------------------------------------------------
9746             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9747                 delete El.cache[eid];
9748                 if(d && Roo.enableListenerCollection){
9749                     E.purgeElement(d);
9750                 }
9751             }
9752         }
9753     }
9754     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9755
9756
9757     // dom is optional
9758     El.Flyweight = function(dom){
9759         this.dom = dom;
9760     };
9761     El.Flyweight.prototype = El.prototype;
9762
9763     El._flyweights = {};
9764     /**
9765      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9766      * the dom node can be overwritten by other code.
9767      * @param {String/HTMLElement} el The dom node or id
9768      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9769      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9770      * @static
9771      * @return {Element} The shared Element object
9772      */
9773     El.fly = function(el, named){
9774         named = named || '_global';
9775         el = Roo.getDom(el);
9776         if(!el){
9777             return null;
9778         }
9779         if(!El._flyweights[named]){
9780             El._flyweights[named] = new El.Flyweight();
9781         }
9782         El._flyweights[named].dom = el;
9783         return El._flyweights[named];
9784     };
9785
9786     /**
9787      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9788      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9789      * Shorthand of {@link Roo.Element#get}
9790      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9791      * @return {Element} The Element object
9792      * @member Roo
9793      * @method get
9794      */
9795     Roo.get = El.get;
9796     /**
9797      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9798      * the dom node can be overwritten by other code.
9799      * Shorthand of {@link Roo.Element#fly}
9800      * @param {String/HTMLElement} el The dom node or id
9801      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9802      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9803      * @static
9804      * @return {Element} The shared Element object
9805      * @member Roo
9806      * @method fly
9807      */
9808     Roo.fly = El.fly;
9809
9810     // speedy lookup for elements never to box adjust
9811     var noBoxAdjust = Roo.isStrict ? {
9812         select:1
9813     } : {
9814         input:1, select:1, textarea:1
9815     };
9816     if(Roo.isIE || Roo.isGecko){
9817         noBoxAdjust['button'] = 1;
9818     }
9819
9820
9821     Roo.EventManager.on(window, 'unload', function(){
9822         delete El.cache;
9823         delete El._flyweights;
9824     });
9825 })();
9826
9827
9828
9829
9830 if(Roo.DomQuery){
9831     Roo.Element.selectorFunction = Roo.DomQuery.select;
9832 }
9833
9834 Roo.Element.select = function(selector, unique, root){
9835     var els;
9836     if(typeof selector == "string"){
9837         els = Roo.Element.selectorFunction(selector, root);
9838     }else if(selector.length !== undefined){
9839         els = selector;
9840     }else{
9841         throw "Invalid selector";
9842     }
9843     if(unique === true){
9844         return new Roo.CompositeElement(els);
9845     }else{
9846         return new Roo.CompositeElementLite(els);
9847     }
9848 };
9849 /**
9850  * Selects elements based on the passed CSS selector to enable working on them as 1.
9851  * @param {String/Array} selector The CSS selector or an array of elements
9852  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9853  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9854  * @return {CompositeElementLite/CompositeElement}
9855  * @member Roo
9856  * @method select
9857  */
9858 Roo.select = Roo.Element.select;
9859
9860
9861
9862
9863
9864
9865
9866
9867
9868
9869
9870
9871
9872
9873 /*
9874  * Based on:
9875  * Ext JS Library 1.1.1
9876  * Copyright(c) 2006-2007, Ext JS, LLC.
9877  *
9878  * Originally Released Under LGPL - original licence link has changed is not relivant.
9879  *
9880  * Fork - LGPL
9881  * <script type="text/javascript">
9882  */
9883
9884
9885
9886 //Notifies Element that fx methods are available
9887 Roo.enableFx = true;
9888
9889 /**
9890  * @class Roo.Fx
9891  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9892  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9893  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9894  * Element effects to work.</p><br/>
9895  *
9896  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9897  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9898  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9899  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9900  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9901  * expected results and should be done with care.</p><br/>
9902  *
9903  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9904  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9905 <pre>
9906 Value  Description
9907 -----  -----------------------------
9908 tl     The top left corner
9909 t      The center of the top edge
9910 tr     The top right corner
9911 l      The center of the left edge
9912 r      The center of the right edge
9913 bl     The bottom left corner
9914 b      The center of the bottom edge
9915 br     The bottom right corner
9916 </pre>
9917  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9918  * below are common options that can be passed to any Fx method.</b>
9919  * @cfg {Function} callback A function called when the effect is finished
9920  * @cfg {Object} scope The scope of the effect function
9921  * @cfg {String} easing A valid Easing value for the effect
9922  * @cfg {String} afterCls A css class to apply after the effect
9923  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9924  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9925  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9926  * effects that end with the element being visually hidden, ignored otherwise)
9927  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9928  * a function which returns such a specification that will be applied to the Element after the effect finishes
9929  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9930  * @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
9931  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9932  */
9933 Roo.Fx = {
9934         /**
9935          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9936          * origin for the slide effect.  This function automatically handles wrapping the element with
9937          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9938          * Usage:
9939          *<pre><code>
9940 // default: slide the element in from the top
9941 el.slideIn();
9942
9943 // custom: slide the element in from the right with a 2-second duration
9944 el.slideIn('r', { duration: 2 });
9945
9946 // common config options shown with default values
9947 el.slideIn('t', {
9948     easing: 'easeOut',
9949     duration: .5
9950 });
9951 </code></pre>
9952          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9953          * @param {Object} options (optional) Object literal with any of the Fx config options
9954          * @return {Roo.Element} The Element
9955          */
9956     slideIn : function(anchor, o){
9957         var el = this.getFxEl();
9958         o = o || {};
9959
9960         el.queueFx(o, function(){
9961
9962             anchor = anchor || "t";
9963
9964             // fix display to visibility
9965             this.fixDisplay();
9966
9967             // restore values after effect
9968             var r = this.getFxRestore();
9969             var b = this.getBox();
9970             // fixed size for slide
9971             this.setSize(b);
9972
9973             // wrap if needed
9974             var wrap = this.fxWrap(r.pos, o, "hidden");
9975
9976             var st = this.dom.style;
9977             st.visibility = "visible";
9978             st.position = "absolute";
9979
9980             // clear out temp styles after slide and unwrap
9981             var after = function(){
9982                 el.fxUnwrap(wrap, r.pos, o);
9983                 st.width = r.width;
9984                 st.height = r.height;
9985                 el.afterFx(o);
9986             };
9987             // time to calc the positions
9988             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9989
9990             switch(anchor.toLowerCase()){
9991                 case "t":
9992                     wrap.setSize(b.width, 0);
9993                     st.left = st.bottom = "0";
9994                     a = {height: bh};
9995                 break;
9996                 case "l":
9997                     wrap.setSize(0, b.height);
9998                     st.right = st.top = "0";
9999                     a = {width: bw};
10000                 break;
10001                 case "r":
10002                     wrap.setSize(0, b.height);
10003                     wrap.setX(b.right);
10004                     st.left = st.top = "0";
10005                     a = {width: bw, points: pt};
10006                 break;
10007                 case "b":
10008                     wrap.setSize(b.width, 0);
10009                     wrap.setY(b.bottom);
10010                     st.left = st.top = "0";
10011                     a = {height: bh, points: pt};
10012                 break;
10013                 case "tl":
10014                     wrap.setSize(0, 0);
10015                     st.right = st.bottom = "0";
10016                     a = {width: bw, height: bh};
10017                 break;
10018                 case "bl":
10019                     wrap.setSize(0, 0);
10020                     wrap.setY(b.y+b.height);
10021                     st.right = st.top = "0";
10022                     a = {width: bw, height: bh, points: pt};
10023                 break;
10024                 case "br":
10025                     wrap.setSize(0, 0);
10026                     wrap.setXY([b.right, b.bottom]);
10027                     st.left = st.top = "0";
10028                     a = {width: bw, height: bh, points: pt};
10029                 break;
10030                 case "tr":
10031                     wrap.setSize(0, 0);
10032                     wrap.setX(b.x+b.width);
10033                     st.left = st.bottom = "0";
10034                     a = {width: bw, height: bh, points: pt};
10035                 break;
10036             }
10037             this.dom.style.visibility = "visible";
10038             wrap.show();
10039
10040             arguments.callee.anim = wrap.fxanim(a,
10041                 o,
10042                 'motion',
10043                 .5,
10044                 'easeOut', after);
10045         });
10046         return this;
10047     },
10048     
10049         /**
10050          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10051          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10052          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10053          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10054          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10055          * Usage:
10056          *<pre><code>
10057 // default: slide the element out to the top
10058 el.slideOut();
10059
10060 // custom: slide the element out to the right with a 2-second duration
10061 el.slideOut('r', { duration: 2 });
10062
10063 // common config options shown with default values
10064 el.slideOut('t', {
10065     easing: 'easeOut',
10066     duration: .5,
10067     remove: false,
10068     useDisplay: false
10069 });
10070 </code></pre>
10071          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10072          * @param {Object} options (optional) Object literal with any of the Fx config options
10073          * @return {Roo.Element} The Element
10074          */
10075     slideOut : function(anchor, o){
10076         var el = this.getFxEl();
10077         o = o || {};
10078
10079         el.queueFx(o, function(){
10080
10081             anchor = anchor || "t";
10082
10083             // restore values after effect
10084             var r = this.getFxRestore();
10085             
10086             var b = this.getBox();
10087             // fixed size for slide
10088             this.setSize(b);
10089
10090             // wrap if needed
10091             var wrap = this.fxWrap(r.pos, o, "visible");
10092
10093             var st = this.dom.style;
10094             st.visibility = "visible";
10095             st.position = "absolute";
10096
10097             wrap.setSize(b);
10098
10099             var after = function(){
10100                 if(o.useDisplay){
10101                     el.setDisplayed(false);
10102                 }else{
10103                     el.hide();
10104                 }
10105
10106                 el.fxUnwrap(wrap, r.pos, o);
10107
10108                 st.width = r.width;
10109                 st.height = r.height;
10110
10111                 el.afterFx(o);
10112             };
10113
10114             var a, zero = {to: 0};
10115             switch(anchor.toLowerCase()){
10116                 case "t":
10117                     st.left = st.bottom = "0";
10118                     a = {height: zero};
10119                 break;
10120                 case "l":
10121                     st.right = st.top = "0";
10122                     a = {width: zero};
10123                 break;
10124                 case "r":
10125                     st.left = st.top = "0";
10126                     a = {width: zero, points: {to:[b.right, b.y]}};
10127                 break;
10128                 case "b":
10129                     st.left = st.top = "0";
10130                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10131                 break;
10132                 case "tl":
10133                     st.right = st.bottom = "0";
10134                     a = {width: zero, height: zero};
10135                 break;
10136                 case "bl":
10137                     st.right = st.top = "0";
10138                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10139                 break;
10140                 case "br":
10141                     st.left = st.top = "0";
10142                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10143                 break;
10144                 case "tr":
10145                     st.left = st.bottom = "0";
10146                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10147                 break;
10148             }
10149
10150             arguments.callee.anim = wrap.fxanim(a,
10151                 o,
10152                 'motion',
10153                 .5,
10154                 "easeOut", after);
10155         });
10156         return this;
10157     },
10158
10159         /**
10160          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10161          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10162          * The element must be removed from the DOM using the 'remove' config option if desired.
10163          * Usage:
10164          *<pre><code>
10165 // default
10166 el.puff();
10167
10168 // common config options shown with default values
10169 el.puff({
10170     easing: 'easeOut',
10171     duration: .5,
10172     remove: false,
10173     useDisplay: false
10174 });
10175 </code></pre>
10176          * @param {Object} options (optional) Object literal with any of the Fx config options
10177          * @return {Roo.Element} The Element
10178          */
10179     puff : function(o){
10180         var el = this.getFxEl();
10181         o = o || {};
10182
10183         el.queueFx(o, function(){
10184             this.clearOpacity();
10185             this.show();
10186
10187             // restore values after effect
10188             var r = this.getFxRestore();
10189             var st = this.dom.style;
10190
10191             var after = function(){
10192                 if(o.useDisplay){
10193                     el.setDisplayed(false);
10194                 }else{
10195                     el.hide();
10196                 }
10197
10198                 el.clearOpacity();
10199
10200                 el.setPositioning(r.pos);
10201                 st.width = r.width;
10202                 st.height = r.height;
10203                 st.fontSize = '';
10204                 el.afterFx(o);
10205             };
10206
10207             var width = this.getWidth();
10208             var height = this.getHeight();
10209
10210             arguments.callee.anim = this.fxanim({
10211                     width : {to: this.adjustWidth(width * 2)},
10212                     height : {to: this.adjustHeight(height * 2)},
10213                     points : {by: [-(width * .5), -(height * .5)]},
10214                     opacity : {to: 0},
10215                     fontSize: {to:200, unit: "%"}
10216                 },
10217                 o,
10218                 'motion',
10219                 .5,
10220                 "easeOut", after);
10221         });
10222         return this;
10223     },
10224
10225         /**
10226          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10227          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10228          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10229          * Usage:
10230          *<pre><code>
10231 // default
10232 el.switchOff();
10233
10234 // all config options shown with default values
10235 el.switchOff({
10236     easing: 'easeIn',
10237     duration: .3,
10238     remove: false,
10239     useDisplay: false
10240 });
10241 </code></pre>
10242          * @param {Object} options (optional) Object literal with any of the Fx config options
10243          * @return {Roo.Element} The Element
10244          */
10245     switchOff : function(o){
10246         var el = this.getFxEl();
10247         o = o || {};
10248
10249         el.queueFx(o, function(){
10250             this.clearOpacity();
10251             this.clip();
10252
10253             // restore values after effect
10254             var r = this.getFxRestore();
10255             var st = this.dom.style;
10256
10257             var after = function(){
10258                 if(o.useDisplay){
10259                     el.setDisplayed(false);
10260                 }else{
10261                     el.hide();
10262                 }
10263
10264                 el.clearOpacity();
10265                 el.setPositioning(r.pos);
10266                 st.width = r.width;
10267                 st.height = r.height;
10268
10269                 el.afterFx(o);
10270             };
10271
10272             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10273                 this.clearOpacity();
10274                 (function(){
10275                     this.fxanim({
10276                         height:{to:1},
10277                         points:{by:[0, this.getHeight() * .5]}
10278                     }, o, 'motion', 0.3, 'easeIn', after);
10279                 }).defer(100, this);
10280             });
10281         });
10282         return this;
10283     },
10284
10285     /**
10286      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10287      * changed using the "attr" config option) and then fading back to the original color. If no original
10288      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10289      * Usage:
10290 <pre><code>
10291 // default: highlight background to yellow
10292 el.highlight();
10293
10294 // custom: highlight foreground text to blue for 2 seconds
10295 el.highlight("0000ff", { attr: 'color', duration: 2 });
10296
10297 // common config options shown with default values
10298 el.highlight("ffff9c", {
10299     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10300     endColor: (current color) or "ffffff",
10301     easing: 'easeIn',
10302     duration: 1
10303 });
10304 </code></pre>
10305      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10306      * @param {Object} options (optional) Object literal with any of the Fx config options
10307      * @return {Roo.Element} The Element
10308      */ 
10309     highlight : function(color, o){
10310         var el = this.getFxEl();
10311         o = o || {};
10312
10313         el.queueFx(o, function(){
10314             color = color || "ffff9c";
10315             attr = o.attr || "backgroundColor";
10316
10317             this.clearOpacity();
10318             this.show();
10319
10320             var origColor = this.getColor(attr);
10321             var restoreColor = this.dom.style[attr];
10322             endColor = (o.endColor || origColor) || "ffffff";
10323
10324             var after = function(){
10325                 el.dom.style[attr] = restoreColor;
10326                 el.afterFx(o);
10327             };
10328
10329             var a = {};
10330             a[attr] = {from: color, to: endColor};
10331             arguments.callee.anim = this.fxanim(a,
10332                 o,
10333                 'color',
10334                 1,
10335                 'easeIn', after);
10336         });
10337         return this;
10338     },
10339
10340    /**
10341     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10342     * Usage:
10343 <pre><code>
10344 // default: a single light blue ripple
10345 el.frame();
10346
10347 // custom: 3 red ripples lasting 3 seconds total
10348 el.frame("ff0000", 3, { duration: 3 });
10349
10350 // common config options shown with default values
10351 el.frame("C3DAF9", 1, {
10352     duration: 1 //duration of entire animation (not each individual ripple)
10353     // Note: Easing is not configurable and will be ignored if included
10354 });
10355 </code></pre>
10356     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10357     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10358     * @param {Object} options (optional) Object literal with any of the Fx config options
10359     * @return {Roo.Element} The Element
10360     */
10361     frame : function(color, count, o){
10362         var el = this.getFxEl();
10363         o = o || {};
10364
10365         el.queueFx(o, function(){
10366             color = color || "#C3DAF9";
10367             if(color.length == 6){
10368                 color = "#" + color;
10369             }
10370             count = count || 1;
10371             duration = o.duration || 1;
10372             this.show();
10373
10374             var b = this.getBox();
10375             var animFn = function(){
10376                 var proxy = this.createProxy({
10377
10378                      style:{
10379                         visbility:"hidden",
10380                         position:"absolute",
10381                         "z-index":"35000", // yee haw
10382                         border:"0px solid " + color
10383                      }
10384                   });
10385                 var scale = Roo.isBorderBox ? 2 : 1;
10386                 proxy.animate({
10387                     top:{from:b.y, to:b.y - 20},
10388                     left:{from:b.x, to:b.x - 20},
10389                     borderWidth:{from:0, to:10},
10390                     opacity:{from:1, to:0},
10391                     height:{from:b.height, to:(b.height + (20*scale))},
10392                     width:{from:b.width, to:(b.width + (20*scale))}
10393                 }, duration, function(){
10394                     proxy.remove();
10395                 });
10396                 if(--count > 0){
10397                      animFn.defer((duration/2)*1000, this);
10398                 }else{
10399                     el.afterFx(o);
10400                 }
10401             };
10402             animFn.call(this);
10403         });
10404         return this;
10405     },
10406
10407    /**
10408     * Creates a pause before any subsequent queued effects begin.  If there are
10409     * no effects queued after the pause it will have no effect.
10410     * Usage:
10411 <pre><code>
10412 el.pause(1);
10413 </code></pre>
10414     * @param {Number} seconds The length of time to pause (in seconds)
10415     * @return {Roo.Element} The Element
10416     */
10417     pause : function(seconds){
10418         var el = this.getFxEl();
10419         var o = {};
10420
10421         el.queueFx(o, function(){
10422             setTimeout(function(){
10423                 el.afterFx(o);
10424             }, seconds * 1000);
10425         });
10426         return this;
10427     },
10428
10429    /**
10430     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10431     * using the "endOpacity" config option.
10432     * Usage:
10433 <pre><code>
10434 // default: fade in from opacity 0 to 100%
10435 el.fadeIn();
10436
10437 // custom: fade in from opacity 0 to 75% over 2 seconds
10438 el.fadeIn({ endOpacity: .75, duration: 2});
10439
10440 // common config options shown with default values
10441 el.fadeIn({
10442     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10443     easing: 'easeOut',
10444     duration: .5
10445 });
10446 </code></pre>
10447     * @param {Object} options (optional) Object literal with any of the Fx config options
10448     * @return {Roo.Element} The Element
10449     */
10450     fadeIn : function(o){
10451         var el = this.getFxEl();
10452         o = o || {};
10453         el.queueFx(o, function(){
10454             this.setOpacity(0);
10455             this.fixDisplay();
10456             this.dom.style.visibility = 'visible';
10457             var to = o.endOpacity || 1;
10458             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10459                 o, null, .5, "easeOut", function(){
10460                 if(to == 1){
10461                     this.clearOpacity();
10462                 }
10463                 el.afterFx(o);
10464             });
10465         });
10466         return this;
10467     },
10468
10469    /**
10470     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10471     * using the "endOpacity" config option.
10472     * Usage:
10473 <pre><code>
10474 // default: fade out from the element's current opacity to 0
10475 el.fadeOut();
10476
10477 // custom: fade out from the element's current opacity to 25% over 2 seconds
10478 el.fadeOut({ endOpacity: .25, duration: 2});
10479
10480 // common config options shown with default values
10481 el.fadeOut({
10482     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10483     easing: 'easeOut',
10484     duration: .5
10485     remove: false,
10486     useDisplay: false
10487 });
10488 </code></pre>
10489     * @param {Object} options (optional) Object literal with any of the Fx config options
10490     * @return {Roo.Element} The Element
10491     */
10492     fadeOut : function(o){
10493         var el = this.getFxEl();
10494         o = o || {};
10495         el.queueFx(o, function(){
10496             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10497                 o, null, .5, "easeOut", function(){
10498                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10499                      this.dom.style.display = "none";
10500                 }else{
10501                      this.dom.style.visibility = "hidden";
10502                 }
10503                 this.clearOpacity();
10504                 el.afterFx(o);
10505             });
10506         });
10507         return this;
10508     },
10509
10510    /**
10511     * Animates the transition of an element's dimensions from a starting height/width
10512     * to an ending height/width.
10513     * Usage:
10514 <pre><code>
10515 // change height and width to 100x100 pixels
10516 el.scale(100, 100);
10517
10518 // common config options shown with default values.  The height and width will default to
10519 // the element's existing values if passed as null.
10520 el.scale(
10521     [element's width],
10522     [element's height], {
10523     easing: 'easeOut',
10524     duration: .35
10525 });
10526 </code></pre>
10527     * @param {Number} width  The new width (pass undefined to keep the original width)
10528     * @param {Number} height  The new height (pass undefined to keep the original height)
10529     * @param {Object} options (optional) Object literal with any of the Fx config options
10530     * @return {Roo.Element} The Element
10531     */
10532     scale : function(w, h, o){
10533         this.shift(Roo.apply({}, o, {
10534             width: w,
10535             height: h
10536         }));
10537         return this;
10538     },
10539
10540    /**
10541     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10542     * Any of these properties not specified in the config object will not be changed.  This effect 
10543     * requires that at least one new dimension, position or opacity setting must be passed in on
10544     * the config object in order for the function to have any effect.
10545     * Usage:
10546 <pre><code>
10547 // slide the element horizontally to x position 200 while changing the height and opacity
10548 el.shift({ x: 200, height: 50, opacity: .8 });
10549
10550 // common config options shown with default values.
10551 el.shift({
10552     width: [element's width],
10553     height: [element's height],
10554     x: [element's x position],
10555     y: [element's y position],
10556     opacity: [element's opacity],
10557     easing: 'easeOut',
10558     duration: .35
10559 });
10560 </code></pre>
10561     * @param {Object} options  Object literal with any of the Fx config options
10562     * @return {Roo.Element} The Element
10563     */
10564     shift : function(o){
10565         var el = this.getFxEl();
10566         o = o || {};
10567         el.queueFx(o, function(){
10568             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10569             if(w !== undefined){
10570                 a.width = {to: this.adjustWidth(w)};
10571             }
10572             if(h !== undefined){
10573                 a.height = {to: this.adjustHeight(h)};
10574             }
10575             if(x !== undefined || y !== undefined){
10576                 a.points = {to: [
10577                     x !== undefined ? x : this.getX(),
10578                     y !== undefined ? y : this.getY()
10579                 ]};
10580             }
10581             if(op !== undefined){
10582                 a.opacity = {to: op};
10583             }
10584             if(o.xy !== undefined){
10585                 a.points = {to: o.xy};
10586             }
10587             arguments.callee.anim = this.fxanim(a,
10588                 o, 'motion', .35, "easeOut", function(){
10589                 el.afterFx(o);
10590             });
10591         });
10592         return this;
10593     },
10594
10595         /**
10596          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10597          * ending point of the effect.
10598          * Usage:
10599          *<pre><code>
10600 // default: slide the element downward while fading out
10601 el.ghost();
10602
10603 // custom: slide the element out to the right with a 2-second duration
10604 el.ghost('r', { duration: 2 });
10605
10606 // common config options shown with default values
10607 el.ghost('b', {
10608     easing: 'easeOut',
10609     duration: .5
10610     remove: false,
10611     useDisplay: false
10612 });
10613 </code></pre>
10614          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10615          * @param {Object} options (optional) Object literal with any of the Fx config options
10616          * @return {Roo.Element} The Element
10617          */
10618     ghost : function(anchor, o){
10619         var el = this.getFxEl();
10620         o = o || {};
10621
10622         el.queueFx(o, function(){
10623             anchor = anchor || "b";
10624
10625             // restore values after effect
10626             var r = this.getFxRestore();
10627             var w = this.getWidth(),
10628                 h = this.getHeight();
10629
10630             var st = this.dom.style;
10631
10632             var after = function(){
10633                 if(o.useDisplay){
10634                     el.setDisplayed(false);
10635                 }else{
10636                     el.hide();
10637                 }
10638
10639                 el.clearOpacity();
10640                 el.setPositioning(r.pos);
10641                 st.width = r.width;
10642                 st.height = r.height;
10643
10644                 el.afterFx(o);
10645             };
10646
10647             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10648             switch(anchor.toLowerCase()){
10649                 case "t":
10650                     pt.by = [0, -h];
10651                 break;
10652                 case "l":
10653                     pt.by = [-w, 0];
10654                 break;
10655                 case "r":
10656                     pt.by = [w, 0];
10657                 break;
10658                 case "b":
10659                     pt.by = [0, h];
10660                 break;
10661                 case "tl":
10662                     pt.by = [-w, -h];
10663                 break;
10664                 case "bl":
10665                     pt.by = [-w, h];
10666                 break;
10667                 case "br":
10668                     pt.by = [w, h];
10669                 break;
10670                 case "tr":
10671                     pt.by = [w, -h];
10672                 break;
10673             }
10674
10675             arguments.callee.anim = this.fxanim(a,
10676                 o,
10677                 'motion',
10678                 .5,
10679                 "easeOut", after);
10680         });
10681         return this;
10682     },
10683
10684         /**
10685          * Ensures that all effects queued after syncFx is called on the element are
10686          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10687          * @return {Roo.Element} The Element
10688          */
10689     syncFx : function(){
10690         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10691             block : false,
10692             concurrent : true,
10693             stopFx : false
10694         });
10695         return this;
10696     },
10697
10698         /**
10699          * Ensures that all effects queued after sequenceFx is called on the element are
10700          * run in sequence.  This is the opposite of {@link #syncFx}.
10701          * @return {Roo.Element} The Element
10702          */
10703     sequenceFx : function(){
10704         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10705             block : false,
10706             concurrent : false,
10707             stopFx : false
10708         });
10709         return this;
10710     },
10711
10712         /* @private */
10713     nextFx : function(){
10714         var ef = this.fxQueue[0];
10715         if(ef){
10716             ef.call(this);
10717         }
10718     },
10719
10720         /**
10721          * Returns true if the element has any effects actively running or queued, else returns false.
10722          * @return {Boolean} True if element has active effects, else false
10723          */
10724     hasActiveFx : function(){
10725         return this.fxQueue && this.fxQueue[0];
10726     },
10727
10728         /**
10729          * Stops any running effects and clears the element's internal effects queue if it contains
10730          * any additional effects that haven't started yet.
10731          * @return {Roo.Element} The Element
10732          */
10733     stopFx : function(){
10734         if(this.hasActiveFx()){
10735             var cur = this.fxQueue[0];
10736             if(cur && cur.anim && cur.anim.isAnimated()){
10737                 this.fxQueue = [cur]; // clear out others
10738                 cur.anim.stop(true);
10739             }
10740         }
10741         return this;
10742     },
10743
10744         /* @private */
10745     beforeFx : function(o){
10746         if(this.hasActiveFx() && !o.concurrent){
10747            if(o.stopFx){
10748                this.stopFx();
10749                return true;
10750            }
10751            return false;
10752         }
10753         return true;
10754     },
10755
10756         /**
10757          * Returns true if the element is currently blocking so that no other effect can be queued
10758          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10759          * used to ensure that an effect initiated by a user action runs to completion prior to the
10760          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10761          * @return {Boolean} True if blocking, else false
10762          */
10763     hasFxBlock : function(){
10764         var q = this.fxQueue;
10765         return q && q[0] && q[0].block;
10766     },
10767
10768         /* @private */
10769     queueFx : function(o, fn){
10770         if(!this.fxQueue){
10771             this.fxQueue = [];
10772         }
10773         if(!this.hasFxBlock()){
10774             Roo.applyIf(o, this.fxDefaults);
10775             if(!o.concurrent){
10776                 var run = this.beforeFx(o);
10777                 fn.block = o.block;
10778                 this.fxQueue.push(fn);
10779                 if(run){
10780                     this.nextFx();
10781                 }
10782             }else{
10783                 fn.call(this);
10784             }
10785         }
10786         return this;
10787     },
10788
10789         /* @private */
10790     fxWrap : function(pos, o, vis){
10791         var wrap;
10792         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10793             var wrapXY;
10794             if(o.fixPosition){
10795                 wrapXY = this.getXY();
10796             }
10797             var div = document.createElement("div");
10798             div.style.visibility = vis;
10799             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10800             wrap.setPositioning(pos);
10801             if(wrap.getStyle("position") == "static"){
10802                 wrap.position("relative");
10803             }
10804             this.clearPositioning('auto');
10805             wrap.clip();
10806             wrap.dom.appendChild(this.dom);
10807             if(wrapXY){
10808                 wrap.setXY(wrapXY);
10809             }
10810         }
10811         return wrap;
10812     },
10813
10814         /* @private */
10815     fxUnwrap : function(wrap, pos, o){
10816         this.clearPositioning();
10817         this.setPositioning(pos);
10818         if(!o.wrap){
10819             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10820             wrap.remove();
10821         }
10822     },
10823
10824         /* @private */
10825     getFxRestore : function(){
10826         var st = this.dom.style;
10827         return {pos: this.getPositioning(), width: st.width, height : st.height};
10828     },
10829
10830         /* @private */
10831     afterFx : function(o){
10832         if(o.afterStyle){
10833             this.applyStyles(o.afterStyle);
10834         }
10835         if(o.afterCls){
10836             this.addClass(o.afterCls);
10837         }
10838         if(o.remove === true){
10839             this.remove();
10840         }
10841         Roo.callback(o.callback, o.scope, [this]);
10842         if(!o.concurrent){
10843             this.fxQueue.shift();
10844             this.nextFx();
10845         }
10846     },
10847
10848         /* @private */
10849     getFxEl : function(){ // support for composite element fx
10850         return Roo.get(this.dom);
10851     },
10852
10853         /* @private */
10854     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10855         animType = animType || 'run';
10856         opt = opt || {};
10857         var anim = Roo.lib.Anim[animType](
10858             this.dom, args,
10859             (opt.duration || defaultDur) || .35,
10860             (opt.easing || defaultEase) || 'easeOut',
10861             function(){
10862                 Roo.callback(cb, this);
10863             },
10864             this
10865         );
10866         opt.anim = anim;
10867         return anim;
10868     }
10869 };
10870
10871 // backwords compat
10872 Roo.Fx.resize = Roo.Fx.scale;
10873
10874 //When included, Roo.Fx is automatically applied to Element so that all basic
10875 //effects are available directly via the Element API
10876 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10877  * Based on:
10878  * Ext JS Library 1.1.1
10879  * Copyright(c) 2006-2007, Ext JS, LLC.
10880  *
10881  * Originally Released Under LGPL - original licence link has changed is not relivant.
10882  *
10883  * Fork - LGPL
10884  * <script type="text/javascript">
10885  */
10886
10887
10888 /**
10889  * @class Roo.CompositeElement
10890  * Standard composite class. Creates a Roo.Element for every element in the collection.
10891  * <br><br>
10892  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10893  * actions will be performed on all the elements in this collection.</b>
10894  * <br><br>
10895  * All methods return <i>this</i> and can be chained.
10896  <pre><code>
10897  var els = Roo.select("#some-el div.some-class", true);
10898  // or select directly from an existing element
10899  var el = Roo.get('some-el');
10900  el.select('div.some-class', true);
10901
10902  els.setWidth(100); // all elements become 100 width
10903  els.hide(true); // all elements fade out and hide
10904  // or
10905  els.setWidth(100).hide(true);
10906  </code></pre>
10907  */
10908 Roo.CompositeElement = function(els){
10909     this.elements = [];
10910     this.addElements(els);
10911 };
10912 Roo.CompositeElement.prototype = {
10913     isComposite: true,
10914     addElements : function(els){
10915         if(!els) return this;
10916         if(typeof els == "string"){
10917             els = Roo.Element.selectorFunction(els);
10918         }
10919         var yels = this.elements;
10920         var index = yels.length-1;
10921         for(var i = 0, len = els.length; i < len; i++) {
10922                 yels[++index] = Roo.get(els[i]);
10923         }
10924         return this;
10925     },
10926
10927     /**
10928     * Clears this composite and adds the elements returned by the passed selector.
10929     * @param {String/Array} els A string CSS selector, an array of elements or an element
10930     * @return {CompositeElement} this
10931     */
10932     fill : function(els){
10933         this.elements = [];
10934         this.add(els);
10935         return this;
10936     },
10937
10938     /**
10939     * Filters this composite to only elements that match the passed selector.
10940     * @param {String} selector A string CSS selector
10941     * @return {CompositeElement} this
10942     */
10943     filter : function(selector){
10944         var els = [];
10945         this.each(function(el){
10946             if(el.is(selector)){
10947                 els[els.length] = el.dom;
10948             }
10949         });
10950         this.fill(els);
10951         return this;
10952     },
10953
10954     invoke : function(fn, args){
10955         var els = this.elements;
10956         for(var i = 0, len = els.length; i < len; i++) {
10957                 Roo.Element.prototype[fn].apply(els[i], args);
10958         }
10959         return this;
10960     },
10961     /**
10962     * Adds elements to this composite.
10963     * @param {String/Array} els A string CSS selector, an array of elements or an element
10964     * @return {CompositeElement} this
10965     */
10966     add : function(els){
10967         if(typeof els == "string"){
10968             this.addElements(Roo.Element.selectorFunction(els));
10969         }else if(els.length !== undefined){
10970             this.addElements(els);
10971         }else{
10972             this.addElements([els]);
10973         }
10974         return this;
10975     },
10976     /**
10977     * Calls the passed function passing (el, this, index) for each element in this composite.
10978     * @param {Function} fn The function to call
10979     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10980     * @return {CompositeElement} this
10981     */
10982     each : function(fn, scope){
10983         var els = this.elements;
10984         for(var i = 0, len = els.length; i < len; i++){
10985             if(fn.call(scope || els[i], els[i], this, i) === false) {
10986                 break;
10987             }
10988         }
10989         return this;
10990     },
10991
10992     /**
10993      * Returns the Element object at the specified index
10994      * @param {Number} index
10995      * @return {Roo.Element}
10996      */
10997     item : function(index){
10998         return this.elements[index] || null;
10999     },
11000
11001     /**
11002      * Returns the first Element
11003      * @return {Roo.Element}
11004      */
11005     first : function(){
11006         return this.item(0);
11007     },
11008
11009     /**
11010      * Returns the last Element
11011      * @return {Roo.Element}
11012      */
11013     last : function(){
11014         return this.item(this.elements.length-1);
11015     },
11016
11017     /**
11018      * Returns the number of elements in this composite
11019      * @return Number
11020      */
11021     getCount : function(){
11022         return this.elements.length;
11023     },
11024
11025     /**
11026      * Returns true if this composite contains the passed element
11027      * @return Boolean
11028      */
11029     contains : function(el){
11030         return this.indexOf(el) !== -1;
11031     },
11032
11033     /**
11034      * Returns true if this composite contains the passed element
11035      * @return Boolean
11036      */
11037     indexOf : function(el){
11038         return this.elements.indexOf(Roo.get(el));
11039     },
11040
11041
11042     /**
11043     * Removes the specified element(s).
11044     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11045     * or an array of any of those.
11046     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11047     * @return {CompositeElement} this
11048     */
11049     removeElement : function(el, removeDom){
11050         if(el instanceof Array){
11051             for(var i = 0, len = el.length; i < len; i++){
11052                 this.removeElement(el[i]);
11053             }
11054             return this;
11055         }
11056         var index = typeof el == 'number' ? el : this.indexOf(el);
11057         if(index !== -1){
11058             if(removeDom){
11059                 var d = this.elements[index];
11060                 if(d.dom){
11061                     d.remove();
11062                 }else{
11063                     d.parentNode.removeChild(d);
11064                 }
11065             }
11066             this.elements.splice(index, 1);
11067         }
11068         return this;
11069     },
11070
11071     /**
11072     * Replaces the specified element with the passed element.
11073     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11074     * to replace.
11075     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11076     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11077     * @return {CompositeElement} this
11078     */
11079     replaceElement : function(el, replacement, domReplace){
11080         var index = typeof el == 'number' ? el : this.indexOf(el);
11081         if(index !== -1){
11082             if(domReplace){
11083                 this.elements[index].replaceWith(replacement);
11084             }else{
11085                 this.elements.splice(index, 1, Roo.get(replacement))
11086             }
11087         }
11088         return this;
11089     },
11090
11091     /**
11092      * Removes all elements.
11093      */
11094     clear : function(){
11095         this.elements = [];
11096     }
11097 };
11098 (function(){
11099     Roo.CompositeElement.createCall = function(proto, fnName){
11100         if(!proto[fnName]){
11101             proto[fnName] = function(){
11102                 return this.invoke(fnName, arguments);
11103             };
11104         }
11105     };
11106     for(var fnName in Roo.Element.prototype){
11107         if(typeof Roo.Element.prototype[fnName] == "function"){
11108             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11109         }
11110     };
11111 })();
11112 /*
11113  * Based on:
11114  * Ext JS Library 1.1.1
11115  * Copyright(c) 2006-2007, Ext JS, LLC.
11116  *
11117  * Originally Released Under LGPL - original licence link has changed is not relivant.
11118  *
11119  * Fork - LGPL
11120  * <script type="text/javascript">
11121  */
11122
11123 /**
11124  * @class Roo.CompositeElementLite
11125  * @extends Roo.CompositeElement
11126  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11127  <pre><code>
11128  var els = Roo.select("#some-el div.some-class");
11129  // or select directly from an existing element
11130  var el = Roo.get('some-el');
11131  el.select('div.some-class');
11132
11133  els.setWidth(100); // all elements become 100 width
11134  els.hide(true); // all elements fade out and hide
11135  // or
11136  els.setWidth(100).hide(true);
11137  </code></pre><br><br>
11138  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11139  * actions will be performed on all the elements in this collection.</b>
11140  */
11141 Roo.CompositeElementLite = function(els){
11142     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11143     this.el = new Roo.Element.Flyweight();
11144 };
11145 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11146     addElements : function(els){
11147         if(els){
11148             if(els instanceof Array){
11149                 this.elements = this.elements.concat(els);
11150             }else{
11151                 var yels = this.elements;
11152                 var index = yels.length-1;
11153                 for(var i = 0, len = els.length; i < len; i++) {
11154                     yels[++index] = els[i];
11155                 }
11156             }
11157         }
11158         return this;
11159     },
11160     invoke : function(fn, args){
11161         var els = this.elements;
11162         var el = this.el;
11163         for(var i = 0, len = els.length; i < len; i++) {
11164             el.dom = els[i];
11165                 Roo.Element.prototype[fn].apply(el, args);
11166         }
11167         return this;
11168     },
11169     /**
11170      * Returns a flyweight Element of the dom element object at the specified index
11171      * @param {Number} index
11172      * @return {Roo.Element}
11173      */
11174     item : function(index){
11175         if(!this.elements[index]){
11176             return null;
11177         }
11178         this.el.dom = this.elements[index];
11179         return this.el;
11180     },
11181
11182     // fixes scope with flyweight
11183     addListener : function(eventName, handler, scope, opt){
11184         var els = this.elements;
11185         for(var i = 0, len = els.length; i < len; i++) {
11186             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11187         }
11188         return this;
11189     },
11190
11191     /**
11192     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11193     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11194     * a reference to the dom node, use el.dom.</b>
11195     * @param {Function} fn The function to call
11196     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11197     * @return {CompositeElement} this
11198     */
11199     each : function(fn, scope){
11200         var els = this.elements;
11201         var el = this.el;
11202         for(var i = 0, len = els.length; i < len; i++){
11203             el.dom = els[i];
11204                 if(fn.call(scope || el, el, this, i) === false){
11205                 break;
11206             }
11207         }
11208         return this;
11209     },
11210
11211     indexOf : function(el){
11212         return this.elements.indexOf(Roo.getDom(el));
11213     },
11214
11215     replaceElement : function(el, replacement, domReplace){
11216         var index = typeof el == 'number' ? el : this.indexOf(el);
11217         if(index !== -1){
11218             replacement = Roo.getDom(replacement);
11219             if(domReplace){
11220                 var d = this.elements[index];
11221                 d.parentNode.insertBefore(replacement, d);
11222                 d.parentNode.removeChild(d);
11223             }
11224             this.elements.splice(index, 1, replacement);
11225         }
11226         return this;
11227     }
11228 });
11229 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11230
11231 /*
11232  * Based on:
11233  * Ext JS Library 1.1.1
11234  * Copyright(c) 2006-2007, Ext JS, LLC.
11235  *
11236  * Originally Released Under LGPL - original licence link has changed is not relivant.
11237  *
11238  * Fork - LGPL
11239  * <script type="text/javascript">
11240  */
11241
11242  
11243
11244 /**
11245  * @class Roo.data.Connection
11246  * @extends Roo.util.Observable
11247  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11248  * either to a configured URL, or to a URL specified at request time.<br><br>
11249  * <p>
11250  * Requests made by this class are asynchronous, and will return immediately. No data from
11251  * the server will be available to the statement immediately following the {@link #request} call.
11252  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11253  * <p>
11254  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11255  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11256  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11257  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11258  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11259  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11260  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11261  * standard DOM methods.
11262  * @constructor
11263  * @param {Object} config a configuration object.
11264  */
11265 Roo.data.Connection = function(config){
11266     Roo.apply(this, config);
11267     this.addEvents({
11268         /**
11269          * @event beforerequest
11270          * Fires before a network request is made to retrieve a data object.
11271          * @param {Connection} conn This Connection object.
11272          * @param {Object} options The options config object passed to the {@link #request} method.
11273          */
11274         "beforerequest" : true,
11275         /**
11276          * @event requestcomplete
11277          * Fires if the request was successfully completed.
11278          * @param {Connection} conn This Connection object.
11279          * @param {Object} response The XHR object containing the response data.
11280          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11281          * @param {Object} options The options config object passed to the {@link #request} method.
11282          */
11283         "requestcomplete" : true,
11284         /**
11285          * @event requestexception
11286          * Fires if an error HTTP status was returned from the server.
11287          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11288          * @param {Connection} conn This Connection object.
11289          * @param {Object} response The XHR object containing the response data.
11290          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11291          * @param {Object} options The options config object passed to the {@link #request} method.
11292          */
11293         "requestexception" : true
11294     });
11295     Roo.data.Connection.superclass.constructor.call(this);
11296 };
11297
11298 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11299     /**
11300      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11301      */
11302     /**
11303      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11304      * extra parameters to each request made by this object. (defaults to undefined)
11305      */
11306     /**
11307      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11308      *  to each request made by this object. (defaults to undefined)
11309      */
11310     /**
11311      * @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)
11312      */
11313     /**
11314      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11315      */
11316     timeout : 30000,
11317     /**
11318      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11319      * @type Boolean
11320      */
11321     autoAbort:false,
11322
11323     /**
11324      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11325      * @type Boolean
11326      */
11327     disableCaching: true,
11328
11329     /**
11330      * Sends an HTTP request to a remote server.
11331      * @param {Object} options An object which may contain the following properties:<ul>
11332      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11333      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11334      * request, a url encoded string or a function to call to get either.</li>
11335      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11336      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11337      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11338      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11339      * <li>options {Object} The parameter to the request call.</li>
11340      * <li>success {Boolean} True if the request succeeded.</li>
11341      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11342      * </ul></li>
11343      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11344      * The callback is passed the following parameters:<ul>
11345      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11346      * <li>options {Object} The parameter to the request call.</li>
11347      * </ul></li>
11348      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11349      * The callback is passed the following parameters:<ul>
11350      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11351      * <li>options {Object} The parameter to the request call.</li>
11352      * </ul></li>
11353      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11354      * for the callback function. Defaults to the browser window.</li>
11355      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11356      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11357      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11358      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11359      * params for the post data. Any params will be appended to the URL.</li>
11360      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11361      * </ul>
11362      * @return {Number} transactionId
11363      */
11364     request : function(o){
11365         if(this.fireEvent("beforerequest", this, o) !== false){
11366             var p = o.params;
11367
11368             if(typeof p == "function"){
11369                 p = p.call(o.scope||window, o);
11370             }
11371             if(typeof p == "object"){
11372                 p = Roo.urlEncode(o.params);
11373             }
11374             if(this.extraParams){
11375                 var extras = Roo.urlEncode(this.extraParams);
11376                 p = p ? (p + '&' + extras) : extras;
11377             }
11378
11379             var url = o.url || this.url;
11380             if(typeof url == 'function'){
11381                 url = url.call(o.scope||window, o);
11382             }
11383
11384             if(o.form){
11385                 var form = Roo.getDom(o.form);
11386                 url = url || form.action;
11387
11388                 var enctype = form.getAttribute("enctype");
11389                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11390                     return this.doFormUpload(o, p, url);
11391                 }
11392                 var f = Roo.lib.Ajax.serializeForm(form);
11393                 p = p ? (p + '&' + f) : f;
11394             }
11395
11396             var hs = o.headers;
11397             if(this.defaultHeaders){
11398                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11399                 if(!o.headers){
11400                     o.headers = hs;
11401                 }
11402             }
11403
11404             var cb = {
11405                 success: this.handleResponse,
11406                 failure: this.handleFailure,
11407                 scope: this,
11408                 argument: {options: o},
11409                 timeout : o.timeout || this.timeout
11410             };
11411
11412             var method = o.method||this.method||(p ? "POST" : "GET");
11413
11414             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11415                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11416             }
11417
11418             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11419                 if(o.autoAbort){
11420                     this.abort();
11421                 }
11422             }else if(this.autoAbort !== false){
11423                 this.abort();
11424             }
11425
11426             if((method == 'GET' && p) || o.xmlData){
11427                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11428                 p = '';
11429             }
11430             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11431             return this.transId;
11432         }else{
11433             Roo.callback(o.callback, o.scope, [o, null, null]);
11434             return null;
11435         }
11436     },
11437
11438     /**
11439      * Determine whether this object has a request outstanding.
11440      * @param {Number} transactionId (Optional) defaults to the last transaction
11441      * @return {Boolean} True if there is an outstanding request.
11442      */
11443     isLoading : function(transId){
11444         if(transId){
11445             return Roo.lib.Ajax.isCallInProgress(transId);
11446         }else{
11447             return this.transId ? true : false;
11448         }
11449     },
11450
11451     /**
11452      * Aborts any outstanding request.
11453      * @param {Number} transactionId (Optional) defaults to the last transaction
11454      */
11455     abort : function(transId){
11456         if(transId || this.isLoading()){
11457             Roo.lib.Ajax.abort(transId || this.transId);
11458         }
11459     },
11460
11461     // private
11462     handleResponse : function(response){
11463         this.transId = false;
11464         var options = response.argument.options;
11465         response.argument = options ? options.argument : null;
11466         this.fireEvent("requestcomplete", this, response, options);
11467         Roo.callback(options.success, options.scope, [response, options]);
11468         Roo.callback(options.callback, options.scope, [options, true, response]);
11469     },
11470
11471     // private
11472     handleFailure : function(response, e){
11473         this.transId = false;
11474         var options = response.argument.options;
11475         response.argument = options ? options.argument : null;
11476         this.fireEvent("requestexception", this, response, options, e);
11477         Roo.callback(options.failure, options.scope, [response, options]);
11478         Roo.callback(options.callback, options.scope, [options, false, response]);
11479     },
11480
11481     // private
11482     doFormUpload : function(o, ps, url){
11483         var id = Roo.id();
11484         var frame = document.createElement('iframe');
11485         frame.id = id;
11486         frame.name = id;
11487         frame.className = 'x-hidden';
11488         if(Roo.isIE){
11489             frame.src = Roo.SSL_SECURE_URL;
11490         }
11491         document.body.appendChild(frame);
11492
11493         if(Roo.isIE){
11494            document.frames[id].name = id;
11495         }
11496
11497         var form = Roo.getDom(o.form);
11498         form.target = id;
11499         form.method = 'POST';
11500         form.enctype = form.encoding = 'multipart/form-data';
11501         if(url){
11502             form.action = url;
11503         }
11504
11505         var hiddens, hd;
11506         if(ps){ // add dynamic params
11507             hiddens = [];
11508             ps = Roo.urlDecode(ps, false);
11509             for(var k in ps){
11510                 if(ps.hasOwnProperty(k)){
11511                     hd = document.createElement('input');
11512                     hd.type = 'hidden';
11513                     hd.name = k;
11514                     hd.value = ps[k];
11515                     form.appendChild(hd);
11516                     hiddens.push(hd);
11517                 }
11518             }
11519         }
11520
11521         function cb(){
11522             var r = {  // bogus response object
11523                 responseText : '',
11524                 responseXML : null
11525             };
11526
11527             r.argument = o ? o.argument : null;
11528
11529             try { //
11530                 var doc;
11531                 if(Roo.isIE){
11532                     doc = frame.contentWindow.document;
11533                 }else {
11534                     doc = (frame.contentDocument || window.frames[id].document);
11535                 }
11536                 if(doc && doc.body){
11537                     r.responseText = doc.body.innerHTML;
11538                 }
11539                 if(doc && doc.XMLDocument){
11540                     r.responseXML = doc.XMLDocument;
11541                 }else {
11542                     r.responseXML = doc;
11543                 }
11544             }
11545             catch(e) {
11546                 // ignore
11547             }
11548
11549             Roo.EventManager.removeListener(frame, 'load', cb, this);
11550
11551             this.fireEvent("requestcomplete", this, r, o);
11552             Roo.callback(o.success, o.scope, [r, o]);
11553             Roo.callback(o.callback, o.scope, [o, true, r]);
11554
11555             setTimeout(function(){document.body.removeChild(frame);}, 100);
11556         }
11557
11558         Roo.EventManager.on(frame, 'load', cb, this);
11559         form.submit();
11560
11561         if(hiddens){ // remove dynamic params
11562             for(var i = 0, len = hiddens.length; i < len; i++){
11563                 form.removeChild(hiddens[i]);
11564             }
11565         }
11566     }
11567 });
11568 /*
11569  * Based on:
11570  * Ext JS Library 1.1.1
11571  * Copyright(c) 2006-2007, Ext JS, LLC.
11572  *
11573  * Originally Released Under LGPL - original licence link has changed is not relivant.
11574  *
11575  * Fork - LGPL
11576  * <script type="text/javascript">
11577  */
11578  
11579 /**
11580  * Global Ajax request class.
11581  * 
11582  * @class Roo.Ajax
11583  * @extends Roo.data.Connection
11584  * @static
11585  * 
11586  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11587  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11588  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11589  * @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)
11590  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11591  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11592  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11593  */
11594 Roo.Ajax = new Roo.data.Connection({
11595     // fix up the docs
11596     /**
11597      * @scope Roo.Ajax
11598      * @type {Boolear} 
11599      */
11600     autoAbort : false,
11601
11602     /**
11603      * Serialize the passed form into a url encoded string
11604      * @scope Roo.Ajax
11605      * @param {String/HTMLElement} form
11606      * @return {String}
11607      */
11608     serializeForm : function(form){
11609         return Roo.lib.Ajax.serializeForm(form);
11610     }
11611 });/*
11612  * Based on:
11613  * Ext JS Library 1.1.1
11614  * Copyright(c) 2006-2007, Ext JS, LLC.
11615  *
11616  * Originally Released Under LGPL - original licence link has changed is not relivant.
11617  *
11618  * Fork - LGPL
11619  * <script type="text/javascript">
11620  */
11621
11622  
11623 /**
11624  * @class Roo.UpdateManager
11625  * @extends Roo.util.Observable
11626  * Provides AJAX-style update for Element object.<br><br>
11627  * Usage:<br>
11628  * <pre><code>
11629  * // Get it from a Roo.Element object
11630  * var el = Roo.get("foo");
11631  * var mgr = el.getUpdateManager();
11632  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11633  * ...
11634  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11635  * <br>
11636  * // or directly (returns the same UpdateManager instance)
11637  * var mgr = new Roo.UpdateManager("myElementId");
11638  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11639  * mgr.on("update", myFcnNeedsToKnow);
11640  * <br>
11641    // short handed call directly from the element object
11642    Roo.get("foo").load({
11643         url: "bar.php",
11644         scripts:true,
11645         params: "for=bar",
11646         text: "Loading Foo..."
11647    });
11648  * </code></pre>
11649  * @constructor
11650  * Create new UpdateManager directly.
11651  * @param {String/HTMLElement/Roo.Element} el The element to update
11652  * @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).
11653  */
11654 Roo.UpdateManager = function(el, forceNew){
11655     el = Roo.get(el);
11656     if(!forceNew && el.updateManager){
11657         return el.updateManager;
11658     }
11659     /**
11660      * The Element object
11661      * @type Roo.Element
11662      */
11663     this.el = el;
11664     /**
11665      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11666      * @type String
11667      */
11668     this.defaultUrl = null;
11669
11670     this.addEvents({
11671         /**
11672          * @event beforeupdate
11673          * Fired before an update is made, return false from your handler and the update is cancelled.
11674          * @param {Roo.Element} el
11675          * @param {String/Object/Function} url
11676          * @param {String/Object} params
11677          */
11678         "beforeupdate": true,
11679         /**
11680          * @event update
11681          * Fired after successful update is made.
11682          * @param {Roo.Element} el
11683          * @param {Object} oResponseObject The response Object
11684          */
11685         "update": true,
11686         /**
11687          * @event failure
11688          * Fired on update failure.
11689          * @param {Roo.Element} el
11690          * @param {Object} oResponseObject The response Object
11691          */
11692         "failure": true
11693     });
11694     var d = Roo.UpdateManager.defaults;
11695     /**
11696      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11697      * @type String
11698      */
11699     this.sslBlankUrl = d.sslBlankUrl;
11700     /**
11701      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11702      * @type Boolean
11703      */
11704     this.disableCaching = d.disableCaching;
11705     /**
11706      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11707      * @type String
11708      */
11709     this.indicatorText = d.indicatorText;
11710     /**
11711      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11712      * @type String
11713      */
11714     this.showLoadIndicator = d.showLoadIndicator;
11715     /**
11716      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11717      * @type Number
11718      */
11719     this.timeout = d.timeout;
11720
11721     /**
11722      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11723      * @type Boolean
11724      */
11725     this.loadScripts = d.loadScripts;
11726
11727     /**
11728      * Transaction object of current executing transaction
11729      */
11730     this.transaction = null;
11731
11732     /**
11733      * @private
11734      */
11735     this.autoRefreshProcId = null;
11736     /**
11737      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11738      * @type Function
11739      */
11740     this.refreshDelegate = this.refresh.createDelegate(this);
11741     /**
11742      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11743      * @type Function
11744      */
11745     this.updateDelegate = this.update.createDelegate(this);
11746     /**
11747      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11748      * @type Function
11749      */
11750     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11751     /**
11752      * @private
11753      */
11754     this.successDelegate = this.processSuccess.createDelegate(this);
11755     /**
11756      * @private
11757      */
11758     this.failureDelegate = this.processFailure.createDelegate(this);
11759
11760     if(!this.renderer){
11761      /**
11762       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11763       */
11764     this.renderer = new Roo.UpdateManager.BasicRenderer();
11765     }
11766     
11767     Roo.UpdateManager.superclass.constructor.call(this);
11768 };
11769
11770 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11771     /**
11772      * Get the Element this UpdateManager is bound to
11773      * @return {Roo.Element} The element
11774      */
11775     getEl : function(){
11776         return this.el;
11777     },
11778     /**
11779      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11780      * @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:
11781 <pre><code>
11782 um.update({<br/>
11783     url: "your-url.php",<br/>
11784     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11785     callback: yourFunction,<br/>
11786     scope: yourObject, //(optional scope)  <br/>
11787     discardUrl: false, <br/>
11788     nocache: false,<br/>
11789     text: "Loading...",<br/>
11790     timeout: 30,<br/>
11791     scripts: false<br/>
11792 });
11793 </code></pre>
11794      * The only required property is url. The optional properties nocache, text and scripts
11795      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11796      * @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}
11797      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11798      * @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.
11799      */
11800     update : function(url, params, callback, discardUrl){
11801         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11802             var method = this.method,
11803                 cfg;
11804             if(typeof url == "object"){ // must be config object
11805                 cfg = url;
11806                 url = cfg.url;
11807                 params = params || cfg.params;
11808                 callback = callback || cfg.callback;
11809                 discardUrl = discardUrl || cfg.discardUrl;
11810                 if(callback && cfg.scope){
11811                     callback = callback.createDelegate(cfg.scope);
11812                 }
11813                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11814                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11815                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11816                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11817                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11818             }
11819             this.showLoading();
11820             if(!discardUrl){
11821                 this.defaultUrl = url;
11822             }
11823             if(typeof url == "function"){
11824                 url = url.call(this);
11825             }
11826
11827             method = method || (params ? "POST" : "GET");
11828             if(method == "GET"){
11829                 url = this.prepareUrl(url);
11830             }
11831
11832             var o = Roo.apply(cfg ||{}, {
11833                 url : url,
11834                 params: params,
11835                 success: this.successDelegate,
11836                 failure: this.failureDelegate,
11837                 callback: undefined,
11838                 timeout: (this.timeout*1000),
11839                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11840             });
11841             Roo.log("updated manager called with timeout of " + o.timeout);
11842             this.transaction = Roo.Ajax.request(o);
11843         }
11844     },
11845
11846     /**
11847      * 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.
11848      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11849      * @param {String/HTMLElement} form The form Id or form element
11850      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11851      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11852      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11853      */
11854     formUpdate : function(form, url, reset, callback){
11855         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11856             if(typeof url == "function"){
11857                 url = url.call(this);
11858             }
11859             form = Roo.getDom(form);
11860             this.transaction = Roo.Ajax.request({
11861                 form: form,
11862                 url:url,
11863                 success: this.successDelegate,
11864                 failure: this.failureDelegate,
11865                 timeout: (this.timeout*1000),
11866                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11867             });
11868             this.showLoading.defer(1, this);
11869         }
11870     },
11871
11872     /**
11873      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11874      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11875      */
11876     refresh : function(callback){
11877         if(this.defaultUrl == null){
11878             return;
11879         }
11880         this.update(this.defaultUrl, null, callback, true);
11881     },
11882
11883     /**
11884      * Set this element to auto refresh.
11885      * @param {Number} interval How often to update (in seconds).
11886      * @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)
11887      * @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}
11888      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11889      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11890      */
11891     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11892         if(refreshNow){
11893             this.update(url || this.defaultUrl, params, callback, true);
11894         }
11895         if(this.autoRefreshProcId){
11896             clearInterval(this.autoRefreshProcId);
11897         }
11898         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11899     },
11900
11901     /**
11902      * Stop auto refresh on this element.
11903      */
11904      stopAutoRefresh : function(){
11905         if(this.autoRefreshProcId){
11906             clearInterval(this.autoRefreshProcId);
11907             delete this.autoRefreshProcId;
11908         }
11909     },
11910
11911     isAutoRefreshing : function(){
11912        return this.autoRefreshProcId ? true : false;
11913     },
11914     /**
11915      * Called to update the element to "Loading" state. Override to perform custom action.
11916      */
11917     showLoading : function(){
11918         if(this.showLoadIndicator){
11919             this.el.update(this.indicatorText);
11920         }
11921     },
11922
11923     /**
11924      * Adds unique parameter to query string if disableCaching = true
11925      * @private
11926      */
11927     prepareUrl : function(url){
11928         if(this.disableCaching){
11929             var append = "_dc=" + (new Date().getTime());
11930             if(url.indexOf("?") !== -1){
11931                 url += "&" + append;
11932             }else{
11933                 url += "?" + append;
11934             }
11935         }
11936         return url;
11937     },
11938
11939     /**
11940      * @private
11941      */
11942     processSuccess : function(response){
11943         this.transaction = null;
11944         if(response.argument.form && response.argument.reset){
11945             try{ // put in try/catch since some older FF releases had problems with this
11946                 response.argument.form.reset();
11947             }catch(e){}
11948         }
11949         if(this.loadScripts){
11950             this.renderer.render(this.el, response, this,
11951                 this.updateComplete.createDelegate(this, [response]));
11952         }else{
11953             this.renderer.render(this.el, response, this);
11954             this.updateComplete(response);
11955         }
11956     },
11957
11958     updateComplete : function(response){
11959         this.fireEvent("update", this.el, response);
11960         if(typeof response.argument.callback == "function"){
11961             response.argument.callback(this.el, true, response);
11962         }
11963     },
11964
11965     /**
11966      * @private
11967      */
11968     processFailure : function(response){
11969         this.transaction = null;
11970         this.fireEvent("failure", this.el, response);
11971         if(typeof response.argument.callback == "function"){
11972             response.argument.callback(this.el, false, response);
11973         }
11974     },
11975
11976     /**
11977      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11978      * @param {Object} renderer The object implementing the render() method
11979      */
11980     setRenderer : function(renderer){
11981         this.renderer = renderer;
11982     },
11983
11984     getRenderer : function(){
11985        return this.renderer;
11986     },
11987
11988     /**
11989      * Set the defaultUrl used for updates
11990      * @param {String/Function} defaultUrl The url or a function to call to get the url
11991      */
11992     setDefaultUrl : function(defaultUrl){
11993         this.defaultUrl = defaultUrl;
11994     },
11995
11996     /**
11997      * Aborts the executing transaction
11998      */
11999     abort : function(){
12000         if(this.transaction){
12001             Roo.Ajax.abort(this.transaction);
12002         }
12003     },
12004
12005     /**
12006      * Returns true if an update is in progress
12007      * @return {Boolean}
12008      */
12009     isUpdating : function(){
12010         if(this.transaction){
12011             return Roo.Ajax.isLoading(this.transaction);
12012         }
12013         return false;
12014     }
12015 });
12016
12017 /**
12018  * @class Roo.UpdateManager.defaults
12019  * @static (not really - but it helps the doc tool)
12020  * The defaults collection enables customizing the default properties of UpdateManager
12021  */
12022    Roo.UpdateManager.defaults = {
12023        /**
12024          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12025          * @type Number
12026          */
12027          timeout : 30,
12028
12029          /**
12030          * True to process scripts by default (Defaults to false).
12031          * @type Boolean
12032          */
12033         loadScripts : false,
12034
12035         /**
12036         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12037         * @type String
12038         */
12039         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12040         /**
12041          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12042          * @type Boolean
12043          */
12044         disableCaching : false,
12045         /**
12046          * Whether to show indicatorText when loading (Defaults to true).
12047          * @type Boolean
12048          */
12049         showLoadIndicator : true,
12050         /**
12051          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12052          * @type String
12053          */
12054         indicatorText : '<div class="loading-indicator">Loading...</div>'
12055    };
12056
12057 /**
12058  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12059  *Usage:
12060  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12061  * @param {String/HTMLElement/Roo.Element} el The element to update
12062  * @param {String} url The url
12063  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12064  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12065  * @static
12066  * @deprecated
12067  * @member Roo.UpdateManager
12068  */
12069 Roo.UpdateManager.updateElement = function(el, url, params, options){
12070     var um = Roo.get(el, true).getUpdateManager();
12071     Roo.apply(um, options);
12072     um.update(url, params, options ? options.callback : null);
12073 };
12074 // alias for backwards compat
12075 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12076 /**
12077  * @class Roo.UpdateManager.BasicRenderer
12078  * Default Content renderer. Updates the elements innerHTML with the responseText.
12079  */
12080 Roo.UpdateManager.BasicRenderer = function(){};
12081
12082 Roo.UpdateManager.BasicRenderer.prototype = {
12083     /**
12084      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12085      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12086      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12087      * @param {Roo.Element} el The element being rendered
12088      * @param {Object} response The YUI Connect response object
12089      * @param {UpdateManager} updateManager The calling update manager
12090      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12091      */
12092      render : function(el, response, updateManager, callback){
12093         el.update(response.responseText, updateManager.loadScripts, callback);
12094     }
12095 };
12096 /*
12097  * Based on:
12098  * Roo JS
12099  * (c)) Alan Knowles
12100  * Licence : LGPL
12101  */
12102
12103
12104 /**
12105  * @class Roo.DomTemplate
12106  * @extends Roo.Template
12107  * An effort at a dom based template engine..
12108  *
12109  * Similar to XTemplate, except it uses dom parsing to create the template..
12110  *
12111  * Supported features:
12112  *
12113  *  Tags:
12114
12115 <pre><code>
12116       {a_variable} - output encoded.
12117       {a_variable.format:("Y-m-d")} - call a method on the variable
12118       {a_variable:raw} - unencoded output
12119       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12120       {a_variable:this.method_on_template(...)} - call a method on the template object.
12121  
12122 </code></pre>
12123  *  The tpl tag:
12124 <pre><code>
12125         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12126         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12127         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12128         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12129   
12130 </code></pre>
12131  *      
12132  */
12133 Roo.DomTemplate = function()
12134 {
12135      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12136      if (this.html) {
12137         this.compile();
12138      }
12139 };
12140
12141
12142 Roo.extend(Roo.DomTemplate, Roo.Template, {
12143     /**
12144      * id counter for sub templates.
12145      */
12146     id : 0,
12147     /**
12148      * flag to indicate if dom parser is inside a pre,
12149      * it will strip whitespace if not.
12150      */
12151     inPre : false,
12152     
12153     /**
12154      * The various sub templates
12155      */
12156     tpls : false,
12157     
12158     
12159     
12160     /**
12161      *
12162      * basic tag replacing syntax
12163      * WORD:WORD()
12164      *
12165      * // you can fake an object call by doing this
12166      *  x.t:(test,tesT) 
12167      * 
12168      */
12169     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12170     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12171     
12172     iterChild : function (node, method) {
12173         
12174         var oldPre = this.inPre;
12175         if (node.tagName == 'PRE') {
12176             this.inPre = true;
12177         }
12178         for( var i = 0; i < node.childNodes.length; i++) {
12179             method.call(this, node.childNodes[i]);
12180         }
12181         this.inPre = oldPre;
12182     },
12183     
12184     
12185     
12186     /**
12187      * compile the template
12188      *
12189      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12190      *
12191      */
12192     compile: function()
12193     {
12194         var s = this.html;
12195         
12196         // covert the html into DOM...
12197         var doc = false;
12198         var div =false;
12199         try {
12200             doc = document.implementation.createHTMLDocument("");
12201             doc.documentElement.innerHTML =   this.html  ;
12202             div = doc.documentElement;
12203         } catch (e) {
12204             // old IE... - nasty -- it causes all sorts of issues.. with
12205             // images getting pulled from server..
12206             div = document.createElement('div');
12207             div.innerHTML = this.html;
12208         }
12209         //doc.documentElement.innerHTML = htmlBody
12210          
12211         
12212         
12213         this.tpls = [];
12214         var _t = this;
12215         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12216         
12217         var tpls = this.tpls;
12218         
12219         // create a top level template from the snippet..
12220         
12221         //Roo.log(div.innerHTML);
12222         
12223         var tpl = {
12224             uid : 'master',
12225             id : this.id++,
12226             attr : false,
12227             value : false,
12228             body : div.innerHTML,
12229             
12230             forCall : false,
12231             execCall : false,
12232             dom : div,
12233             isTop : true
12234             
12235         };
12236         tpls.unshift(tpl);
12237         
12238         
12239         // compile them...
12240         this.tpls = [];
12241         Roo.each(tpls, function(tp){
12242             this.compileTpl(tp);
12243             this.tpls[tp.id] = tp;
12244         }, this);
12245         
12246         this.master = tpls[0];
12247         return this;
12248         
12249         
12250     },
12251     
12252     compileNode : function(node, istop) {
12253         // test for
12254         //Roo.log(node);
12255         
12256         
12257         // skip anything not a tag..
12258         if (node.nodeType != 1) {
12259             if (node.nodeType == 3 && !this.inPre) {
12260                 // reduce white space..
12261                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12262                 
12263             }
12264             return;
12265         }
12266         
12267         var tpl = {
12268             uid : false,
12269             id : false,
12270             attr : false,
12271             value : false,
12272             body : '',
12273             
12274             forCall : false,
12275             execCall : false,
12276             dom : false,
12277             isTop : istop
12278             
12279             
12280         };
12281         
12282         
12283         switch(true) {
12284             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12285             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12286             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12287             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12288             // no default..
12289         }
12290         
12291         
12292         if (!tpl.attr) {
12293             // just itterate children..
12294             this.iterChild(node,this.compileNode);
12295             return;
12296         }
12297         tpl.uid = this.id++;
12298         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12299         node.removeAttribute('roo-'+ tpl.attr);
12300         if (tpl.attr != 'name') {
12301             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12302             node.parentNode.replaceChild(placeholder,  node);
12303         } else {
12304             
12305             var placeholder =  document.createElement('span');
12306             placeholder.className = 'roo-tpl-' + tpl.value;
12307             node.parentNode.replaceChild(placeholder,  node);
12308         }
12309         
12310         // parent now sees '{domtplXXXX}
12311         this.iterChild(node,this.compileNode);
12312         
12313         // we should now have node body...
12314         var div = document.createElement('div');
12315         div.appendChild(node);
12316         tpl.dom = node;
12317         // this has the unfortunate side effect of converting tagged attributes
12318         // eg. href="{...}" into %7C...%7D
12319         // this has been fixed by searching for those combo's although it's a bit hacky..
12320         
12321         
12322         tpl.body = div.innerHTML;
12323         
12324         
12325          
12326         tpl.id = tpl.uid;
12327         switch(tpl.attr) {
12328             case 'for' :
12329                 switch (tpl.value) {
12330                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12331                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12332                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12333                 }
12334                 break;
12335             
12336             case 'exec':
12337                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12338                 break;
12339             
12340             case 'if':     
12341                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12342                 break;
12343             
12344             case 'name':
12345                 tpl.id  = tpl.value; // replace non characters???
12346                 break;
12347             
12348         }
12349         
12350         
12351         this.tpls.push(tpl);
12352         
12353         
12354         
12355     },
12356     
12357     
12358     
12359     
12360     /**
12361      * Compile a segment of the template into a 'sub-template'
12362      *
12363      * 
12364      * 
12365      *
12366      */
12367     compileTpl : function(tpl)
12368     {
12369         var fm = Roo.util.Format;
12370         var useF = this.disableFormats !== true;
12371         
12372         var sep = Roo.isGecko ? "+\n" : ",\n";
12373         
12374         var undef = function(str) {
12375             Roo.debug && Roo.log("Property not found :"  + str);
12376             return '';
12377         };
12378           
12379         //Roo.log(tpl.body);
12380         
12381         
12382         
12383         var fn = function(m, lbrace, name, format, args)
12384         {
12385             //Roo.log("ARGS");
12386             //Roo.log(arguments);
12387             args = args ? args.replace(/\\'/g,"'") : args;
12388             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12389             if (typeof(format) == 'undefined') {
12390                 format =  'htmlEncode'; 
12391             }
12392             if (format == 'raw' ) {
12393                 format = false;
12394             }
12395             
12396             if(name.substr(0, 6) == 'domtpl'){
12397                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12398             }
12399             
12400             // build an array of options to determine if value is undefined..
12401             
12402             // basically get 'xxxx.yyyy' then do
12403             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12404             //    (function () { Roo.log("Property not found"); return ''; })() :
12405             //    ......
12406             
12407             var udef_ar = [];
12408             var lookfor = '';
12409             Roo.each(name.split('.'), function(st) {
12410                 lookfor += (lookfor.length ? '.': '') + st;
12411                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12412             });
12413             
12414             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12415             
12416             
12417             if(format && useF){
12418                 
12419                 args = args ? ',' + args : "";
12420                  
12421                 if(format.substr(0, 5) != "this."){
12422                     format = "fm." + format + '(';
12423                 }else{
12424                     format = 'this.call("'+ format.substr(5) + '", ';
12425                     args = ", values";
12426                 }
12427                 
12428                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12429             }
12430              
12431             if (args && args.length) {
12432                 // called with xxyx.yuu:(test,test)
12433                 // change to ()
12434                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12435             }
12436             // raw.. - :raw modifier..
12437             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12438             
12439         };
12440         var body;
12441         // branched to use + in gecko and [].join() in others
12442         if(Roo.isGecko){
12443             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12444                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12445                     "';};};";
12446         }else{
12447             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12448             body.push(tpl.body.replace(/(\r\n|\n)/g,
12449                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12450             body.push("'].join('');};};");
12451             body = body.join('');
12452         }
12453         
12454         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12455        
12456         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12457         eval(body);
12458         
12459         return this;
12460     },
12461      
12462     /**
12463      * same as applyTemplate, except it's done to one of the subTemplates
12464      * when using named templates, you can do:
12465      *
12466      * var str = pl.applySubTemplate('your-name', values);
12467      *
12468      * 
12469      * @param {Number} id of the template
12470      * @param {Object} values to apply to template
12471      * @param {Object} parent (normaly the instance of this object)
12472      */
12473     applySubTemplate : function(id, values, parent)
12474     {
12475         
12476         
12477         var t = this.tpls[id];
12478         
12479         
12480         try { 
12481             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12482                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12483                 return '';
12484             }
12485         } catch(e) {
12486             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12487             Roo.log(values);
12488           
12489             return '';
12490         }
12491         try { 
12492             
12493             if(t.execCall && t.execCall.call(this, values, parent)){
12494                 return '';
12495             }
12496         } catch(e) {
12497             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12498             Roo.log(values);
12499             return '';
12500         }
12501         
12502         try {
12503             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12504             parent = t.target ? values : parent;
12505             if(t.forCall && vs instanceof Array){
12506                 var buf = [];
12507                 for(var i = 0, len = vs.length; i < len; i++){
12508                     try {
12509                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12510                     } catch (e) {
12511                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12512                         Roo.log(e.body);
12513                         //Roo.log(t.compiled);
12514                         Roo.log(vs[i]);
12515                     }   
12516                 }
12517                 return buf.join('');
12518             }
12519         } catch (e) {
12520             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12521             Roo.log(values);
12522             return '';
12523         }
12524         try {
12525             return t.compiled.call(this, vs, parent);
12526         } catch (e) {
12527             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12528             Roo.log(e.body);
12529             //Roo.log(t.compiled);
12530             Roo.log(values);
12531             return '';
12532         }
12533     },
12534
12535    
12536
12537     applyTemplate : function(values){
12538         return this.master.compiled.call(this, values, {});
12539         //var s = this.subs;
12540     },
12541
12542     apply : function(){
12543         return this.applyTemplate.apply(this, arguments);
12544     }
12545
12546  });
12547
12548 Roo.DomTemplate.from = function(el){
12549     el = Roo.getDom(el);
12550     return new Roo.Domtemplate(el.value || el.innerHTML);
12551 };/*
12552  * Based on:
12553  * Ext JS Library 1.1.1
12554  * Copyright(c) 2006-2007, Ext JS, LLC.
12555  *
12556  * Originally Released Under LGPL - original licence link has changed is not relivant.
12557  *
12558  * Fork - LGPL
12559  * <script type="text/javascript">
12560  */
12561
12562 /**
12563  * @class Roo.util.DelayedTask
12564  * Provides a convenient method of performing setTimeout where a new
12565  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12566  * You can use this class to buffer
12567  * the keypress events for a certain number of milliseconds, and perform only if they stop
12568  * for that amount of time.
12569  * @constructor The parameters to this constructor serve as defaults and are not required.
12570  * @param {Function} fn (optional) The default function to timeout
12571  * @param {Object} scope (optional) The default scope of that timeout
12572  * @param {Array} args (optional) The default Array of arguments
12573  */
12574 Roo.util.DelayedTask = function(fn, scope, args){
12575     var id = null, d, t;
12576
12577     var call = function(){
12578         var now = new Date().getTime();
12579         if(now - t >= d){
12580             clearInterval(id);
12581             id = null;
12582             fn.apply(scope, args || []);
12583         }
12584     };
12585     /**
12586      * Cancels any pending timeout and queues a new one
12587      * @param {Number} delay The milliseconds to delay
12588      * @param {Function} newFn (optional) Overrides function passed to constructor
12589      * @param {Object} newScope (optional) Overrides scope passed to constructor
12590      * @param {Array} newArgs (optional) Overrides args passed to constructor
12591      */
12592     this.delay = function(delay, newFn, newScope, newArgs){
12593         if(id && delay != d){
12594             this.cancel();
12595         }
12596         d = delay;
12597         t = new Date().getTime();
12598         fn = newFn || fn;
12599         scope = newScope || scope;
12600         args = newArgs || args;
12601         if(!id){
12602             id = setInterval(call, d);
12603         }
12604     };
12605
12606     /**
12607      * Cancel the last queued timeout
12608      */
12609     this.cancel = function(){
12610         if(id){
12611             clearInterval(id);
12612             id = null;
12613         }
12614     };
12615 };/*
12616  * Based on:
12617  * Ext JS Library 1.1.1
12618  * Copyright(c) 2006-2007, Ext JS, LLC.
12619  *
12620  * Originally Released Under LGPL - original licence link has changed is not relivant.
12621  *
12622  * Fork - LGPL
12623  * <script type="text/javascript">
12624  */
12625  
12626  
12627 Roo.util.TaskRunner = function(interval){
12628     interval = interval || 10;
12629     var tasks = [], removeQueue = [];
12630     var id = 0;
12631     var running = false;
12632
12633     var stopThread = function(){
12634         running = false;
12635         clearInterval(id);
12636         id = 0;
12637     };
12638
12639     var startThread = function(){
12640         if(!running){
12641             running = true;
12642             id = setInterval(runTasks, interval);
12643         }
12644     };
12645
12646     var removeTask = function(task){
12647         removeQueue.push(task);
12648         if(task.onStop){
12649             task.onStop();
12650         }
12651     };
12652
12653     var runTasks = function(){
12654         if(removeQueue.length > 0){
12655             for(var i = 0, len = removeQueue.length; i < len; i++){
12656                 tasks.remove(removeQueue[i]);
12657             }
12658             removeQueue = [];
12659             if(tasks.length < 1){
12660                 stopThread();
12661                 return;
12662             }
12663         }
12664         var now = new Date().getTime();
12665         for(var i = 0, len = tasks.length; i < len; ++i){
12666             var t = tasks[i];
12667             var itime = now - t.taskRunTime;
12668             if(t.interval <= itime){
12669                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12670                 t.taskRunTime = now;
12671                 if(rt === false || t.taskRunCount === t.repeat){
12672                     removeTask(t);
12673                     return;
12674                 }
12675             }
12676             if(t.duration && t.duration <= (now - t.taskStartTime)){
12677                 removeTask(t);
12678             }
12679         }
12680     };
12681
12682     /**
12683      * Queues a new task.
12684      * @param {Object} task
12685      */
12686     this.start = function(task){
12687         tasks.push(task);
12688         task.taskStartTime = new Date().getTime();
12689         task.taskRunTime = 0;
12690         task.taskRunCount = 0;
12691         startThread();
12692         return task;
12693     };
12694
12695     this.stop = function(task){
12696         removeTask(task);
12697         return task;
12698     };
12699
12700     this.stopAll = function(){
12701         stopThread();
12702         for(var i = 0, len = tasks.length; i < len; i++){
12703             if(tasks[i].onStop){
12704                 tasks[i].onStop();
12705             }
12706         }
12707         tasks = [];
12708         removeQueue = [];
12709     };
12710 };
12711
12712 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12713  * Based on:
12714  * Ext JS Library 1.1.1
12715  * Copyright(c) 2006-2007, Ext JS, LLC.
12716  *
12717  * Originally Released Under LGPL - original licence link has changed is not relivant.
12718  *
12719  * Fork - LGPL
12720  * <script type="text/javascript">
12721  */
12722
12723  
12724 /**
12725  * @class Roo.util.MixedCollection
12726  * @extends Roo.util.Observable
12727  * A Collection class that maintains both numeric indexes and keys and exposes events.
12728  * @constructor
12729  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12730  * collection (defaults to false)
12731  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12732  * and return the key value for that item.  This is used when available to look up the key on items that
12733  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12734  * equivalent to providing an implementation for the {@link #getKey} method.
12735  */
12736 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12737     this.items = [];
12738     this.map = {};
12739     this.keys = [];
12740     this.length = 0;
12741     this.addEvents({
12742         /**
12743          * @event clear
12744          * Fires when the collection is cleared.
12745          */
12746         "clear" : true,
12747         /**
12748          * @event add
12749          * Fires when an item is added to the collection.
12750          * @param {Number} index The index at which the item was added.
12751          * @param {Object} o The item added.
12752          * @param {String} key The key associated with the added item.
12753          */
12754         "add" : true,
12755         /**
12756          * @event replace
12757          * Fires when an item is replaced in the collection.
12758          * @param {String} key he key associated with the new added.
12759          * @param {Object} old The item being replaced.
12760          * @param {Object} new The new item.
12761          */
12762         "replace" : true,
12763         /**
12764          * @event remove
12765          * Fires when an item is removed from the collection.
12766          * @param {Object} o The item being removed.
12767          * @param {String} key (optional) The key associated with the removed item.
12768          */
12769         "remove" : true,
12770         "sort" : true
12771     });
12772     this.allowFunctions = allowFunctions === true;
12773     if(keyFn){
12774         this.getKey = keyFn;
12775     }
12776     Roo.util.MixedCollection.superclass.constructor.call(this);
12777 };
12778
12779 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12780     allowFunctions : false,
12781     
12782 /**
12783  * Adds an item to the collection.
12784  * @param {String} key The key to associate with the item
12785  * @param {Object} o The item to add.
12786  * @return {Object} The item added.
12787  */
12788     add : function(key, o){
12789         if(arguments.length == 1){
12790             o = arguments[0];
12791             key = this.getKey(o);
12792         }
12793         if(typeof key == "undefined" || key === null){
12794             this.length++;
12795             this.items.push(o);
12796             this.keys.push(null);
12797         }else{
12798             var old = this.map[key];
12799             if(old){
12800                 return this.replace(key, o);
12801             }
12802             this.length++;
12803             this.items.push(o);
12804             this.map[key] = o;
12805             this.keys.push(key);
12806         }
12807         this.fireEvent("add", this.length-1, o, key);
12808         return o;
12809     },
12810        
12811 /**
12812   * MixedCollection has a generic way to fetch keys if you implement getKey.
12813 <pre><code>
12814 // normal way
12815 var mc = new Roo.util.MixedCollection();
12816 mc.add(someEl.dom.id, someEl);
12817 mc.add(otherEl.dom.id, otherEl);
12818 //and so on
12819
12820 // using getKey
12821 var mc = new Roo.util.MixedCollection();
12822 mc.getKey = function(el){
12823    return el.dom.id;
12824 };
12825 mc.add(someEl);
12826 mc.add(otherEl);
12827
12828 // or via the constructor
12829 var mc = new Roo.util.MixedCollection(false, function(el){
12830    return el.dom.id;
12831 });
12832 mc.add(someEl);
12833 mc.add(otherEl);
12834 </code></pre>
12835  * @param o {Object} The item for which to find the key.
12836  * @return {Object} The key for the passed item.
12837  */
12838     getKey : function(o){
12839          return o.id; 
12840     },
12841    
12842 /**
12843  * Replaces an item in the collection.
12844  * @param {String} key The key associated with the item to replace, or the item to replace.
12845  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12846  * @return {Object}  The new item.
12847  */
12848     replace : function(key, o){
12849         if(arguments.length == 1){
12850             o = arguments[0];
12851             key = this.getKey(o);
12852         }
12853         var old = this.item(key);
12854         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12855              return this.add(key, o);
12856         }
12857         var index = this.indexOfKey(key);
12858         this.items[index] = o;
12859         this.map[key] = o;
12860         this.fireEvent("replace", key, old, o);
12861         return o;
12862     },
12863    
12864 /**
12865  * Adds all elements of an Array or an Object to the collection.
12866  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12867  * an Array of values, each of which are added to the collection.
12868  */
12869     addAll : function(objs){
12870         if(arguments.length > 1 || objs instanceof Array){
12871             var args = arguments.length > 1 ? arguments : objs;
12872             for(var i = 0, len = args.length; i < len; i++){
12873                 this.add(args[i]);
12874             }
12875         }else{
12876             for(var key in objs){
12877                 if(this.allowFunctions || typeof objs[key] != "function"){
12878                     this.add(key, objs[key]);
12879                 }
12880             }
12881         }
12882     },
12883    
12884 /**
12885  * Executes the specified function once for every item in the collection, passing each
12886  * item as the first and only parameter. returning false from the function will stop the iteration.
12887  * @param {Function} fn The function to execute for each item.
12888  * @param {Object} scope (optional) The scope in which to execute the function.
12889  */
12890     each : function(fn, scope){
12891         var items = [].concat(this.items); // each safe for removal
12892         for(var i = 0, len = items.length; i < len; i++){
12893             if(fn.call(scope || items[i], items[i], i, len) === false){
12894                 break;
12895             }
12896         }
12897     },
12898    
12899 /**
12900  * Executes the specified function once for every key in the collection, passing each
12901  * key, and its associated item as the first two parameters.
12902  * @param {Function} fn The function to execute for each item.
12903  * @param {Object} scope (optional) The scope in which to execute the function.
12904  */
12905     eachKey : function(fn, scope){
12906         for(var i = 0, len = this.keys.length; i < len; i++){
12907             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12908         }
12909     },
12910    
12911 /**
12912  * Returns the first item in the collection which elicits a true return value from the
12913  * passed selection function.
12914  * @param {Function} fn The selection function to execute for each item.
12915  * @param {Object} scope (optional) The scope in which to execute the function.
12916  * @return {Object} The first item in the collection which returned true from the selection function.
12917  */
12918     find : function(fn, scope){
12919         for(var i = 0, len = this.items.length; i < len; i++){
12920             if(fn.call(scope || window, this.items[i], this.keys[i])){
12921                 return this.items[i];
12922             }
12923         }
12924         return null;
12925     },
12926    
12927 /**
12928  * Inserts an item at the specified index in the collection.
12929  * @param {Number} index The index to insert the item at.
12930  * @param {String} key The key to associate with the new item, or the item itself.
12931  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12932  * @return {Object} The item inserted.
12933  */
12934     insert : function(index, key, o){
12935         if(arguments.length == 2){
12936             o = arguments[1];
12937             key = this.getKey(o);
12938         }
12939         if(index >= this.length){
12940             return this.add(key, o);
12941         }
12942         this.length++;
12943         this.items.splice(index, 0, o);
12944         if(typeof key != "undefined" && key != null){
12945             this.map[key] = o;
12946         }
12947         this.keys.splice(index, 0, key);
12948         this.fireEvent("add", index, o, key);
12949         return o;
12950     },
12951    
12952 /**
12953  * Removed an item from the collection.
12954  * @param {Object} o The item to remove.
12955  * @return {Object} The item removed.
12956  */
12957     remove : function(o){
12958         return this.removeAt(this.indexOf(o));
12959     },
12960    
12961 /**
12962  * Remove an item from a specified index in the collection.
12963  * @param {Number} index The index within the collection of the item to remove.
12964  */
12965     removeAt : function(index){
12966         if(index < this.length && index >= 0){
12967             this.length--;
12968             var o = this.items[index];
12969             this.items.splice(index, 1);
12970             var key = this.keys[index];
12971             if(typeof key != "undefined"){
12972                 delete this.map[key];
12973             }
12974             this.keys.splice(index, 1);
12975             this.fireEvent("remove", o, key);
12976         }
12977     },
12978    
12979 /**
12980  * Removed an item associated with the passed key fom the collection.
12981  * @param {String} key The key of the item to remove.
12982  */
12983     removeKey : function(key){
12984         return this.removeAt(this.indexOfKey(key));
12985     },
12986    
12987 /**
12988  * Returns the number of items in the collection.
12989  * @return {Number} the number of items in the collection.
12990  */
12991     getCount : function(){
12992         return this.length; 
12993     },
12994    
12995 /**
12996  * Returns index within the collection of the passed Object.
12997  * @param {Object} o The item to find the index of.
12998  * @return {Number} index of the item.
12999  */
13000     indexOf : function(o){
13001         if(!this.items.indexOf){
13002             for(var i = 0, len = this.items.length; i < len; i++){
13003                 if(this.items[i] == o) return i;
13004             }
13005             return -1;
13006         }else{
13007             return this.items.indexOf(o);
13008         }
13009     },
13010    
13011 /**
13012  * Returns index within the collection of the passed key.
13013  * @param {String} key The key to find the index of.
13014  * @return {Number} index of the key.
13015  */
13016     indexOfKey : function(key){
13017         if(!this.keys.indexOf){
13018             for(var i = 0, len = this.keys.length; i < len; i++){
13019                 if(this.keys[i] == key) return i;
13020             }
13021             return -1;
13022         }else{
13023             return this.keys.indexOf(key);
13024         }
13025     },
13026    
13027 /**
13028  * Returns the item associated with the passed key OR index. Key has priority over index.
13029  * @param {String/Number} key The key or index of the item.
13030  * @return {Object} The item associated with the passed key.
13031  */
13032     item : function(key){
13033         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13034         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13035     },
13036     
13037 /**
13038  * Returns the item at the specified index.
13039  * @param {Number} index The index of the item.
13040  * @return {Object}
13041  */
13042     itemAt : function(index){
13043         return this.items[index];
13044     },
13045     
13046 /**
13047  * Returns the item associated with the passed key.
13048  * @param {String/Number} key The key of the item.
13049  * @return {Object} The item associated with the passed key.
13050  */
13051     key : function(key){
13052         return this.map[key];
13053     },
13054    
13055 /**
13056  * Returns true if the collection contains the passed Object as an item.
13057  * @param {Object} o  The Object to look for in the collection.
13058  * @return {Boolean} True if the collection contains the Object as an item.
13059  */
13060     contains : function(o){
13061         return this.indexOf(o) != -1;
13062     },
13063    
13064 /**
13065  * Returns true if the collection contains the passed Object as a key.
13066  * @param {String} key The key to look for in the collection.
13067  * @return {Boolean} True if the collection contains the Object as a key.
13068  */
13069     containsKey : function(key){
13070         return typeof this.map[key] != "undefined";
13071     },
13072    
13073 /**
13074  * Removes all items from the collection.
13075  */
13076     clear : function(){
13077         this.length = 0;
13078         this.items = [];
13079         this.keys = [];
13080         this.map = {};
13081         this.fireEvent("clear");
13082     },
13083    
13084 /**
13085  * Returns the first item in the collection.
13086  * @return {Object} the first item in the collection..
13087  */
13088     first : function(){
13089         return this.items[0]; 
13090     },
13091    
13092 /**
13093  * Returns the last item in the collection.
13094  * @return {Object} the last item in the collection..
13095  */
13096     last : function(){
13097         return this.items[this.length-1];   
13098     },
13099     
13100     _sort : function(property, dir, fn){
13101         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13102         fn = fn || function(a, b){
13103             return a-b;
13104         };
13105         var c = [], k = this.keys, items = this.items;
13106         for(var i = 0, len = items.length; i < len; i++){
13107             c[c.length] = {key: k[i], value: items[i], index: i};
13108         }
13109         c.sort(function(a, b){
13110             var v = fn(a[property], b[property]) * dsc;
13111             if(v == 0){
13112                 v = (a.index < b.index ? -1 : 1);
13113             }
13114             return v;
13115         });
13116         for(var i = 0, len = c.length; i < len; i++){
13117             items[i] = c[i].value;
13118             k[i] = c[i].key;
13119         }
13120         this.fireEvent("sort", this);
13121     },
13122     
13123     /**
13124      * Sorts this collection with the passed comparison function
13125      * @param {String} direction (optional) "ASC" or "DESC"
13126      * @param {Function} fn (optional) comparison function
13127      */
13128     sort : function(dir, fn){
13129         this._sort("value", dir, fn);
13130     },
13131     
13132     /**
13133      * Sorts this collection by keys
13134      * @param {String} direction (optional) "ASC" or "DESC"
13135      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13136      */
13137     keySort : function(dir, fn){
13138         this._sort("key", dir, fn || function(a, b){
13139             return String(a).toUpperCase()-String(b).toUpperCase();
13140         });
13141     },
13142     
13143     /**
13144      * Returns a range of items in this collection
13145      * @param {Number} startIndex (optional) defaults to 0
13146      * @param {Number} endIndex (optional) default to the last item
13147      * @return {Array} An array of items
13148      */
13149     getRange : function(start, end){
13150         var items = this.items;
13151         if(items.length < 1){
13152             return [];
13153         }
13154         start = start || 0;
13155         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13156         var r = [];
13157         if(start <= end){
13158             for(var i = start; i <= end; i++) {
13159                     r[r.length] = items[i];
13160             }
13161         }else{
13162             for(var i = start; i >= end; i--) {
13163                     r[r.length] = items[i];
13164             }
13165         }
13166         return r;
13167     },
13168         
13169     /**
13170      * Filter the <i>objects</i> in this collection by a specific property. 
13171      * Returns a new collection that has been filtered.
13172      * @param {String} property A property on your objects
13173      * @param {String/RegExp} value Either string that the property values 
13174      * should start with or a RegExp to test against the property
13175      * @return {MixedCollection} The new filtered collection
13176      */
13177     filter : function(property, value){
13178         if(!value.exec){ // not a regex
13179             value = String(value);
13180             if(value.length == 0){
13181                 return this.clone();
13182             }
13183             value = new RegExp("^" + Roo.escapeRe(value), "i");
13184         }
13185         return this.filterBy(function(o){
13186             return o && value.test(o[property]);
13187         });
13188         },
13189     
13190     /**
13191      * Filter by a function. * Returns a new collection that has been filtered.
13192      * The passed function will be called with each 
13193      * object in the collection. If the function returns true, the value is included 
13194      * otherwise it is filtered.
13195      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13196      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13197      * @return {MixedCollection} The new filtered collection
13198      */
13199     filterBy : function(fn, scope){
13200         var r = new Roo.util.MixedCollection();
13201         r.getKey = this.getKey;
13202         var k = this.keys, it = this.items;
13203         for(var i = 0, len = it.length; i < len; i++){
13204             if(fn.call(scope||this, it[i], k[i])){
13205                                 r.add(k[i], it[i]);
13206                         }
13207         }
13208         return r;
13209     },
13210     
13211     /**
13212      * Creates a duplicate of this collection
13213      * @return {MixedCollection}
13214      */
13215     clone : function(){
13216         var r = new Roo.util.MixedCollection();
13217         var k = this.keys, it = this.items;
13218         for(var i = 0, len = it.length; i < len; i++){
13219             r.add(k[i], it[i]);
13220         }
13221         r.getKey = this.getKey;
13222         return r;
13223     }
13224 });
13225 /**
13226  * Returns the item associated with the passed key or index.
13227  * @method
13228  * @param {String/Number} key The key or index of the item.
13229  * @return {Object} The item associated with the passed key.
13230  */
13231 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13232  * Based on:
13233  * Ext JS Library 1.1.1
13234  * Copyright(c) 2006-2007, Ext JS, LLC.
13235  *
13236  * Originally Released Under LGPL - original licence link has changed is not relivant.
13237  *
13238  * Fork - LGPL
13239  * <script type="text/javascript">
13240  */
13241 /**
13242  * @class Roo.util.JSON
13243  * Modified version of Douglas Crockford"s json.js that doesn"t
13244  * mess with the Object prototype 
13245  * http://www.json.org/js.html
13246  * @singleton
13247  */
13248 Roo.util.JSON = new (function(){
13249     var useHasOwn = {}.hasOwnProperty ? true : false;
13250     
13251     // crashes Safari in some instances
13252     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13253     
13254     var pad = function(n) {
13255         return n < 10 ? "0" + n : n;
13256     };
13257     
13258     var m = {
13259         "\b": '\\b',
13260         "\t": '\\t',
13261         "\n": '\\n',
13262         "\f": '\\f',
13263         "\r": '\\r',
13264         '"' : '\\"',
13265         "\\": '\\\\'
13266     };
13267
13268     var encodeString = function(s){
13269         if (/["\\\x00-\x1f]/.test(s)) {
13270             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13271                 var c = m[b];
13272                 if(c){
13273                     return c;
13274                 }
13275                 c = b.charCodeAt();
13276                 return "\\u00" +
13277                     Math.floor(c / 16).toString(16) +
13278                     (c % 16).toString(16);
13279             }) + '"';
13280         }
13281         return '"' + s + '"';
13282     };
13283     
13284     var encodeArray = function(o){
13285         var a = ["["], b, i, l = o.length, v;
13286             for (i = 0; i < l; i += 1) {
13287                 v = o[i];
13288                 switch (typeof v) {
13289                     case "undefined":
13290                     case "function":
13291                     case "unknown":
13292                         break;
13293                     default:
13294                         if (b) {
13295                             a.push(',');
13296                         }
13297                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13298                         b = true;
13299                 }
13300             }
13301             a.push("]");
13302             return a.join("");
13303     };
13304     
13305     var encodeDate = function(o){
13306         return '"' + o.getFullYear() + "-" +
13307                 pad(o.getMonth() + 1) + "-" +
13308                 pad(o.getDate()) + "T" +
13309                 pad(o.getHours()) + ":" +
13310                 pad(o.getMinutes()) + ":" +
13311                 pad(o.getSeconds()) + '"';
13312     };
13313     
13314     /**
13315      * Encodes an Object, Array or other value
13316      * @param {Mixed} o The variable to encode
13317      * @return {String} The JSON string
13318      */
13319     this.encode = function(o)
13320     {
13321         // should this be extended to fully wrap stringify..
13322         
13323         if(typeof o == "undefined" || o === null){
13324             return "null";
13325         }else if(o instanceof Array){
13326             return encodeArray(o);
13327         }else if(o instanceof Date){
13328             return encodeDate(o);
13329         }else if(typeof o == "string"){
13330             return encodeString(o);
13331         }else if(typeof o == "number"){
13332             return isFinite(o) ? String(o) : "null";
13333         }else if(typeof o == "boolean"){
13334             return String(o);
13335         }else {
13336             var a = ["{"], b, i, v;
13337             for (i in o) {
13338                 if(!useHasOwn || o.hasOwnProperty(i)) {
13339                     v = o[i];
13340                     switch (typeof v) {
13341                     case "undefined":
13342                     case "function":
13343                     case "unknown":
13344                         break;
13345                     default:
13346                         if(b){
13347                             a.push(',');
13348                         }
13349                         a.push(this.encode(i), ":",
13350                                 v === null ? "null" : this.encode(v));
13351                         b = true;
13352                     }
13353                 }
13354             }
13355             a.push("}");
13356             return a.join("");
13357         }
13358     };
13359     
13360     /**
13361      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13362      * @param {String} json The JSON string
13363      * @return {Object} The resulting object
13364      */
13365     this.decode = function(json){
13366         
13367         return  /** eval:var:json */ eval("(" + json + ')');
13368     };
13369 })();
13370 /** 
13371  * Shorthand for {@link Roo.util.JSON#encode}
13372  * @member Roo encode 
13373  * @method */
13374 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13375 /** 
13376  * Shorthand for {@link Roo.util.JSON#decode}
13377  * @member Roo decode 
13378  * @method */
13379 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13380 /*
13381  * Based on:
13382  * Ext JS Library 1.1.1
13383  * Copyright(c) 2006-2007, Ext JS, LLC.
13384  *
13385  * Originally Released Under LGPL - original licence link has changed is not relivant.
13386  *
13387  * Fork - LGPL
13388  * <script type="text/javascript">
13389  */
13390  
13391 /**
13392  * @class Roo.util.Format
13393  * Reusable data formatting functions
13394  * @singleton
13395  */
13396 Roo.util.Format = function(){
13397     var trimRe = /^\s+|\s+$/g;
13398     return {
13399         /**
13400          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13401          * @param {String} value The string to truncate
13402          * @param {Number} length The maximum length to allow before truncating
13403          * @return {String} The converted text
13404          */
13405         ellipsis : function(value, len){
13406             if(value && value.length > len){
13407                 return value.substr(0, len-3)+"...";
13408             }
13409             return value;
13410         },
13411
13412         /**
13413          * Checks a reference and converts it to empty string if it is undefined
13414          * @param {Mixed} value Reference to check
13415          * @return {Mixed} Empty string if converted, otherwise the original value
13416          */
13417         undef : function(value){
13418             return typeof value != "undefined" ? value : "";
13419         },
13420
13421         /**
13422          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13423          * @param {String} value The string to encode
13424          * @return {String} The encoded text
13425          */
13426         htmlEncode : function(value){
13427             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13428         },
13429
13430         /**
13431          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13432          * @param {String} value The string to decode
13433          * @return {String} The decoded text
13434          */
13435         htmlDecode : function(value){
13436             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13437         },
13438
13439         /**
13440          * Trims any whitespace from either side of a string
13441          * @param {String} value The text to trim
13442          * @return {String} The trimmed text
13443          */
13444         trim : function(value){
13445             return String(value).replace(trimRe, "");
13446         },
13447
13448         /**
13449          * Returns a substring from within an original string
13450          * @param {String} value The original text
13451          * @param {Number} start The start index of the substring
13452          * @param {Number} length The length of the substring
13453          * @return {String} The substring
13454          */
13455         substr : function(value, start, length){
13456             return String(value).substr(start, length);
13457         },
13458
13459         /**
13460          * Converts a string to all lower case letters
13461          * @param {String} value The text to convert
13462          * @return {String} The converted text
13463          */
13464         lowercase : function(value){
13465             return String(value).toLowerCase();
13466         },
13467
13468         /**
13469          * Converts a string to all upper case letters
13470          * @param {String} value The text to convert
13471          * @return {String} The converted text
13472          */
13473         uppercase : function(value){
13474             return String(value).toUpperCase();
13475         },
13476
13477         /**
13478          * Converts the first character only of a string to upper case
13479          * @param {String} value The text to convert
13480          * @return {String} The converted text
13481          */
13482         capitalize : function(value){
13483             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13484         },
13485
13486         // private
13487         call : function(value, fn){
13488             if(arguments.length > 2){
13489                 var args = Array.prototype.slice.call(arguments, 2);
13490                 args.unshift(value);
13491                  
13492                 return /** eval:var:value */  eval(fn).apply(window, args);
13493             }else{
13494                 /** eval:var:value */
13495                 return /** eval:var:value */ eval(fn).call(window, value);
13496             }
13497         },
13498
13499        
13500         /**
13501          * safer version of Math.toFixed..??/
13502          * @param {Number/String} value The numeric value to format
13503          * @param {Number/String} value Decimal places 
13504          * @return {String} The formatted currency string
13505          */
13506         toFixed : function(v, n)
13507         {
13508             // why not use to fixed - precision is buggered???
13509             if (!n) {
13510                 return Math.round(v-0);
13511             }
13512             var fact = Math.pow(10,n+1);
13513             v = (Math.round((v-0)*fact))/fact;
13514             var z = (''+fact).substring(2);
13515             if (v == Math.floor(v)) {
13516                 return Math.floor(v) + '.' + z;
13517             }
13518             
13519             // now just padd decimals..
13520             var ps = String(v).split('.');
13521             var fd = (ps[1] + z);
13522             var r = fd.substring(0,n); 
13523             var rm = fd.substring(n); 
13524             if (rm < 5) {
13525                 return ps[0] + '.' + r;
13526             }
13527             r*=1; // turn it into a number;
13528             r++;
13529             if (String(r).length != n) {
13530                 ps[0]*=1;
13531                 ps[0]++;
13532                 r = String(r).substring(1); // chop the end off.
13533             }
13534             
13535             return ps[0] + '.' + r;
13536              
13537         },
13538         
13539         /**
13540          * Format a number as US currency
13541          * @param {Number/String} value The numeric value to format
13542          * @return {String} The formatted currency string
13543          */
13544         usMoney : function(v){
13545             return '$' + Roo.util.Format.number(v);
13546         },
13547         
13548         /**
13549          * Format a number
13550          * eventually this should probably emulate php's number_format
13551          * @param {Number/String} value The numeric value to format
13552          * @param {Number} decimals number of decimal places
13553          * @return {String} The formatted currency string
13554          */
13555         number : function(v,decimals)
13556         {
13557             // multiply and round.
13558             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13559             var mul = Math.pow(10, decimals);
13560             var zero = String(mul).substring(1);
13561             v = (Math.round((v-0)*mul))/mul;
13562             
13563             // if it's '0' number.. then
13564             
13565             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13566             v = String(v);
13567             var ps = v.split('.');
13568             var whole = ps[0];
13569             
13570             
13571             var r = /(\d+)(\d{3})/;
13572             // add comma's
13573             while (r.test(whole)) {
13574                 whole = whole.replace(r, '$1' + ',' + '$2');
13575             }
13576             
13577             
13578             var sub = ps[1] ?
13579                     // has decimals..
13580                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13581                     // does not have decimals
13582                     (decimals ? ('.' + zero) : '');
13583             
13584             
13585             return whole + sub ;
13586         },
13587         
13588         /**
13589          * Parse a value into a formatted date using the specified format pattern.
13590          * @param {Mixed} value The value to format
13591          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13592          * @return {String} The formatted date string
13593          */
13594         date : function(v, format){
13595             if(!v){
13596                 return "";
13597             }
13598             if(!(v instanceof Date)){
13599                 v = new Date(Date.parse(v));
13600             }
13601             return v.dateFormat(format || "m/d/Y");
13602         },
13603
13604         /**
13605          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13606          * @param {String} format Any valid date format string
13607          * @return {Function} The date formatting function
13608          */
13609         dateRenderer : function(format){
13610             return function(v){
13611                 return Roo.util.Format.date(v, format);  
13612             };
13613         },
13614
13615         // private
13616         stripTagsRE : /<\/?[^>]+>/gi,
13617         
13618         /**
13619          * Strips all HTML tags
13620          * @param {Mixed} value The text from which to strip tags
13621          * @return {String} The stripped text
13622          */
13623         stripTags : function(v){
13624             return !v ? v : String(v).replace(this.stripTagsRE, "");
13625         }
13626     };
13627 }();/*
13628  * Based on:
13629  * Ext JS Library 1.1.1
13630  * Copyright(c) 2006-2007, Ext JS, LLC.
13631  *
13632  * Originally Released Under LGPL - original licence link has changed is not relivant.
13633  *
13634  * Fork - LGPL
13635  * <script type="text/javascript">
13636  */
13637
13638
13639  
13640
13641 /**
13642  * @class Roo.MasterTemplate
13643  * @extends Roo.Template
13644  * Provides a template that can have child templates. The syntax is:
13645 <pre><code>
13646 var t = new Roo.MasterTemplate(
13647         '&lt;select name="{name}"&gt;',
13648                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13649         '&lt;/select&gt;'
13650 );
13651 t.add('options', {value: 'foo', text: 'bar'});
13652 // or you can add multiple child elements in one shot
13653 t.addAll('options', [
13654     {value: 'foo', text: 'bar'},
13655     {value: 'foo2', text: 'bar2'},
13656     {value: 'foo3', text: 'bar3'}
13657 ]);
13658 // then append, applying the master template values
13659 t.append('my-form', {name: 'my-select'});
13660 </code></pre>
13661 * A name attribute for the child template is not required if you have only one child
13662 * template or you want to refer to them by index.
13663  */
13664 Roo.MasterTemplate = function(){
13665     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13666     this.originalHtml = this.html;
13667     var st = {};
13668     var m, re = this.subTemplateRe;
13669     re.lastIndex = 0;
13670     var subIndex = 0;
13671     while(m = re.exec(this.html)){
13672         var name = m[1], content = m[2];
13673         st[subIndex] = {
13674             name: name,
13675             index: subIndex,
13676             buffer: [],
13677             tpl : new Roo.Template(content)
13678         };
13679         if(name){
13680             st[name] = st[subIndex];
13681         }
13682         st[subIndex].tpl.compile();
13683         st[subIndex].tpl.call = this.call.createDelegate(this);
13684         subIndex++;
13685     }
13686     this.subCount = subIndex;
13687     this.subs = st;
13688 };
13689 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13690     /**
13691     * The regular expression used to match sub templates
13692     * @type RegExp
13693     * @property
13694     */
13695     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13696
13697     /**
13698      * Applies the passed values to a child template.
13699      * @param {String/Number} name (optional) The name or index of the child template
13700      * @param {Array/Object} values The values to be applied to the template
13701      * @return {MasterTemplate} this
13702      */
13703      add : function(name, values){
13704         if(arguments.length == 1){
13705             values = arguments[0];
13706             name = 0;
13707         }
13708         var s = this.subs[name];
13709         s.buffer[s.buffer.length] = s.tpl.apply(values);
13710         return this;
13711     },
13712
13713     /**
13714      * Applies all the passed values to a child template.
13715      * @param {String/Number} name (optional) The name or index of the child template
13716      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13717      * @param {Boolean} reset (optional) True to reset the template first
13718      * @return {MasterTemplate} this
13719      */
13720     fill : function(name, values, reset){
13721         var a = arguments;
13722         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13723             values = a[0];
13724             name = 0;
13725             reset = a[1];
13726         }
13727         if(reset){
13728             this.reset();
13729         }
13730         for(var i = 0, len = values.length; i < len; i++){
13731             this.add(name, values[i]);
13732         }
13733         return this;
13734     },
13735
13736     /**
13737      * Resets the template for reuse
13738      * @return {MasterTemplate} this
13739      */
13740      reset : function(){
13741         var s = this.subs;
13742         for(var i = 0; i < this.subCount; i++){
13743             s[i].buffer = [];
13744         }
13745         return this;
13746     },
13747
13748     applyTemplate : function(values){
13749         var s = this.subs;
13750         var replaceIndex = -1;
13751         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13752             return s[++replaceIndex].buffer.join("");
13753         });
13754         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13755     },
13756
13757     apply : function(){
13758         return this.applyTemplate.apply(this, arguments);
13759     },
13760
13761     compile : function(){return this;}
13762 });
13763
13764 /**
13765  * Alias for fill().
13766  * @method
13767  */
13768 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13769  /**
13770  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13771  * var tpl = Roo.MasterTemplate.from('element-id');
13772  * @param {String/HTMLElement} el
13773  * @param {Object} config
13774  * @static
13775  */
13776 Roo.MasterTemplate.from = function(el, config){
13777     el = Roo.getDom(el);
13778     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13779 };/*
13780  * Based on:
13781  * Ext JS Library 1.1.1
13782  * Copyright(c) 2006-2007, Ext JS, LLC.
13783  *
13784  * Originally Released Under LGPL - original licence link has changed is not relivant.
13785  *
13786  * Fork - LGPL
13787  * <script type="text/javascript">
13788  */
13789
13790  
13791 /**
13792  * @class Roo.util.CSS
13793  * Utility class for manipulating CSS rules
13794  * @singleton
13795  */
13796 Roo.util.CSS = function(){
13797         var rules = null;
13798         var doc = document;
13799
13800     var camelRe = /(-[a-z])/gi;
13801     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13802
13803    return {
13804    /**
13805     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13806     * tag and appended to the HEAD of the document.
13807     * @param {String|Object} cssText The text containing the css rules
13808     * @param {String} id An id to add to the stylesheet for later removal
13809     * @return {StyleSheet}
13810     */
13811     createStyleSheet : function(cssText, id){
13812         var ss;
13813         var head = doc.getElementsByTagName("head")[0];
13814         var nrules = doc.createElement("style");
13815         nrules.setAttribute("type", "text/css");
13816         if(id){
13817             nrules.setAttribute("id", id);
13818         }
13819         if (typeof(cssText) != 'string') {
13820             // support object maps..
13821             // not sure if this a good idea.. 
13822             // perhaps it should be merged with the general css handling
13823             // and handle js style props.
13824             var cssTextNew = [];
13825             for(var n in cssText) {
13826                 var citems = [];
13827                 for(var k in cssText[n]) {
13828                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13829                 }
13830                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13831                 
13832             }
13833             cssText = cssTextNew.join("\n");
13834             
13835         }
13836        
13837        
13838        if(Roo.isIE){
13839            head.appendChild(nrules);
13840            ss = nrules.styleSheet;
13841            ss.cssText = cssText;
13842        }else{
13843            try{
13844                 nrules.appendChild(doc.createTextNode(cssText));
13845            }catch(e){
13846                nrules.cssText = cssText; 
13847            }
13848            head.appendChild(nrules);
13849            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13850        }
13851        this.cacheStyleSheet(ss);
13852        return ss;
13853    },
13854
13855    /**
13856     * Removes a style or link tag by id
13857     * @param {String} id The id of the tag
13858     */
13859    removeStyleSheet : function(id){
13860        var existing = doc.getElementById(id);
13861        if(existing){
13862            existing.parentNode.removeChild(existing);
13863        }
13864    },
13865
13866    /**
13867     * Dynamically swaps an existing stylesheet reference for a new one
13868     * @param {String} id The id of an existing link tag to remove
13869     * @param {String} url The href of the new stylesheet to include
13870     */
13871    swapStyleSheet : function(id, url){
13872        this.removeStyleSheet(id);
13873        var ss = doc.createElement("link");
13874        ss.setAttribute("rel", "stylesheet");
13875        ss.setAttribute("type", "text/css");
13876        ss.setAttribute("id", id);
13877        ss.setAttribute("href", url);
13878        doc.getElementsByTagName("head")[0].appendChild(ss);
13879    },
13880    
13881    /**
13882     * Refresh the rule cache if you have dynamically added stylesheets
13883     * @return {Object} An object (hash) of rules indexed by selector
13884     */
13885    refreshCache : function(){
13886        return this.getRules(true);
13887    },
13888
13889    // private
13890    cacheStyleSheet : function(stylesheet){
13891        if(!rules){
13892            rules = {};
13893        }
13894        try{// try catch for cross domain access issue
13895            var ssRules = stylesheet.cssRules || stylesheet.rules;
13896            for(var j = ssRules.length-1; j >= 0; --j){
13897                rules[ssRules[j].selectorText] = ssRules[j];
13898            }
13899        }catch(e){}
13900    },
13901    
13902    /**
13903     * Gets all css rules for the document
13904     * @param {Boolean} refreshCache true to refresh the internal cache
13905     * @return {Object} An object (hash) of rules indexed by selector
13906     */
13907    getRules : function(refreshCache){
13908                 if(rules == null || refreshCache){
13909                         rules = {};
13910                         var ds = doc.styleSheets;
13911                         for(var i =0, len = ds.length; i < len; i++){
13912                             try{
13913                         this.cacheStyleSheet(ds[i]);
13914                     }catch(e){} 
13915                 }
13916                 }
13917                 return rules;
13918         },
13919         
13920         /**
13921     * Gets an an individual CSS rule by selector(s)
13922     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13923     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13924     * @return {CSSRule} The CSS rule or null if one is not found
13925     */
13926    getRule : function(selector, refreshCache){
13927                 var rs = this.getRules(refreshCache);
13928                 if(!(selector instanceof Array)){
13929                     return rs[selector];
13930                 }
13931                 for(var i = 0; i < selector.length; i++){
13932                         if(rs[selector[i]]){
13933                                 return rs[selector[i]];
13934                         }
13935                 }
13936                 return null;
13937         },
13938         
13939         
13940         /**
13941     * Updates a rule property
13942     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13943     * @param {String} property The css property
13944     * @param {String} value The new value for the property
13945     * @return {Boolean} true If a rule was found and updated
13946     */
13947    updateRule : function(selector, property, value){
13948                 if(!(selector instanceof Array)){
13949                         var rule = this.getRule(selector);
13950                         if(rule){
13951                                 rule.style[property.replace(camelRe, camelFn)] = value;
13952                                 return true;
13953                         }
13954                 }else{
13955                         for(var i = 0; i < selector.length; i++){
13956                                 if(this.updateRule(selector[i], property, value)){
13957                                         return true;
13958                                 }
13959                         }
13960                 }
13961                 return false;
13962         }
13963    };   
13964 }();/*
13965  * Based on:
13966  * Ext JS Library 1.1.1
13967  * Copyright(c) 2006-2007, Ext JS, LLC.
13968  *
13969  * Originally Released Under LGPL - original licence link has changed is not relivant.
13970  *
13971  * Fork - LGPL
13972  * <script type="text/javascript">
13973  */
13974
13975  
13976
13977 /**
13978  * @class Roo.util.ClickRepeater
13979  * @extends Roo.util.Observable
13980  * 
13981  * A wrapper class which can be applied to any element. Fires a "click" event while the
13982  * mouse is pressed. The interval between firings may be specified in the config but
13983  * defaults to 10 milliseconds.
13984  * 
13985  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13986  * 
13987  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13988  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13989  * Similar to an autorepeat key delay.
13990  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13991  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13992  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13993  *           "interval" and "delay" are ignored. "immediate" is honored.
13994  * @cfg {Boolean} preventDefault True to prevent the default click event
13995  * @cfg {Boolean} stopDefault True to stop the default click event
13996  * 
13997  * @history
13998  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13999  *     2007-02-02 jvs Renamed to ClickRepeater
14000  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14001  *
14002  *  @constructor
14003  * @param {String/HTMLElement/Element} el The element to listen on
14004  * @param {Object} config
14005  **/
14006 Roo.util.ClickRepeater = function(el, config)
14007 {
14008     this.el = Roo.get(el);
14009     this.el.unselectable();
14010
14011     Roo.apply(this, config);
14012
14013     this.addEvents({
14014     /**
14015      * @event mousedown
14016      * Fires when the mouse button is depressed.
14017      * @param {Roo.util.ClickRepeater} this
14018      */
14019         "mousedown" : true,
14020     /**
14021      * @event click
14022      * Fires on a specified interval during the time the element is pressed.
14023      * @param {Roo.util.ClickRepeater} this
14024      */
14025         "click" : true,
14026     /**
14027      * @event mouseup
14028      * Fires when the mouse key is released.
14029      * @param {Roo.util.ClickRepeater} this
14030      */
14031         "mouseup" : true
14032     });
14033
14034     this.el.on("mousedown", this.handleMouseDown, this);
14035     if(this.preventDefault || this.stopDefault){
14036         this.el.on("click", function(e){
14037             if(this.preventDefault){
14038                 e.preventDefault();
14039             }
14040             if(this.stopDefault){
14041                 e.stopEvent();
14042             }
14043         }, this);
14044     }
14045
14046     // allow inline handler
14047     if(this.handler){
14048         this.on("click", this.handler,  this.scope || this);
14049     }
14050
14051     Roo.util.ClickRepeater.superclass.constructor.call(this);
14052 };
14053
14054 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14055     interval : 20,
14056     delay: 250,
14057     preventDefault : true,
14058     stopDefault : false,
14059     timer : 0,
14060
14061     // private
14062     handleMouseDown : function(){
14063         clearTimeout(this.timer);
14064         this.el.blur();
14065         if(this.pressClass){
14066             this.el.addClass(this.pressClass);
14067         }
14068         this.mousedownTime = new Date();
14069
14070         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14071         this.el.on("mouseout", this.handleMouseOut, this);
14072
14073         this.fireEvent("mousedown", this);
14074         this.fireEvent("click", this);
14075         
14076         this.timer = this.click.defer(this.delay || this.interval, this);
14077     },
14078
14079     // private
14080     click : function(){
14081         this.fireEvent("click", this);
14082         this.timer = this.click.defer(this.getInterval(), this);
14083     },
14084
14085     // private
14086     getInterval: function(){
14087         if(!this.accelerate){
14088             return this.interval;
14089         }
14090         var pressTime = this.mousedownTime.getElapsed();
14091         if(pressTime < 500){
14092             return 400;
14093         }else if(pressTime < 1700){
14094             return 320;
14095         }else if(pressTime < 2600){
14096             return 250;
14097         }else if(pressTime < 3500){
14098             return 180;
14099         }else if(pressTime < 4400){
14100             return 140;
14101         }else if(pressTime < 5300){
14102             return 80;
14103         }else if(pressTime < 6200){
14104             return 50;
14105         }else{
14106             return 10;
14107         }
14108     },
14109
14110     // private
14111     handleMouseOut : function(){
14112         clearTimeout(this.timer);
14113         if(this.pressClass){
14114             this.el.removeClass(this.pressClass);
14115         }
14116         this.el.on("mouseover", this.handleMouseReturn, this);
14117     },
14118
14119     // private
14120     handleMouseReturn : function(){
14121         this.el.un("mouseover", this.handleMouseReturn);
14122         if(this.pressClass){
14123             this.el.addClass(this.pressClass);
14124         }
14125         this.click();
14126     },
14127
14128     // private
14129     handleMouseUp : function(){
14130         clearTimeout(this.timer);
14131         this.el.un("mouseover", this.handleMouseReturn);
14132         this.el.un("mouseout", this.handleMouseOut);
14133         Roo.get(document).un("mouseup", this.handleMouseUp);
14134         this.el.removeClass(this.pressClass);
14135         this.fireEvent("mouseup", this);
14136     }
14137 });/*
14138  * Based on:
14139  * Ext JS Library 1.1.1
14140  * Copyright(c) 2006-2007, Ext JS, LLC.
14141  *
14142  * Originally Released Under LGPL - original licence link has changed is not relivant.
14143  *
14144  * Fork - LGPL
14145  * <script type="text/javascript">
14146  */
14147
14148  
14149 /**
14150  * @class Roo.KeyNav
14151  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14152  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14153  * way to implement custom navigation schemes for any UI component.</p>
14154  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14155  * pageUp, pageDown, del, home, end.  Usage:</p>
14156  <pre><code>
14157 var nav = new Roo.KeyNav("my-element", {
14158     "left" : function(e){
14159         this.moveLeft(e.ctrlKey);
14160     },
14161     "right" : function(e){
14162         this.moveRight(e.ctrlKey);
14163     },
14164     "enter" : function(e){
14165         this.save();
14166     },
14167     scope : this
14168 });
14169 </code></pre>
14170  * @constructor
14171  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14172  * @param {Object} config The config
14173  */
14174 Roo.KeyNav = function(el, config){
14175     this.el = Roo.get(el);
14176     Roo.apply(this, config);
14177     if(!this.disabled){
14178         this.disabled = true;
14179         this.enable();
14180     }
14181 };
14182
14183 Roo.KeyNav.prototype = {
14184     /**
14185      * @cfg {Boolean} disabled
14186      * True to disable this KeyNav instance (defaults to false)
14187      */
14188     disabled : false,
14189     /**
14190      * @cfg {String} defaultEventAction
14191      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14192      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14193      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14194      */
14195     defaultEventAction: "stopEvent",
14196     /**
14197      * @cfg {Boolean} forceKeyDown
14198      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14199      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14200      * handle keydown instead of keypress.
14201      */
14202     forceKeyDown : false,
14203
14204     // private
14205     prepareEvent : function(e){
14206         var k = e.getKey();
14207         var h = this.keyToHandler[k];
14208         //if(h && this[h]){
14209         //    e.stopPropagation();
14210         //}
14211         if(Roo.isSafari && h && k >= 37 && k <= 40){
14212             e.stopEvent();
14213         }
14214     },
14215
14216     // private
14217     relay : function(e){
14218         var k = e.getKey();
14219         var h = this.keyToHandler[k];
14220         if(h && this[h]){
14221             if(this.doRelay(e, this[h], h) !== true){
14222                 e[this.defaultEventAction]();
14223             }
14224         }
14225     },
14226
14227     // private
14228     doRelay : function(e, h, hname){
14229         return h.call(this.scope || this, e);
14230     },
14231
14232     // possible handlers
14233     enter : false,
14234     left : false,
14235     right : false,
14236     up : false,
14237     down : false,
14238     tab : false,
14239     esc : false,
14240     pageUp : false,
14241     pageDown : false,
14242     del : false,
14243     home : false,
14244     end : false,
14245
14246     // quick lookup hash
14247     keyToHandler : {
14248         37 : "left",
14249         39 : "right",
14250         38 : "up",
14251         40 : "down",
14252         33 : "pageUp",
14253         34 : "pageDown",
14254         46 : "del",
14255         36 : "home",
14256         35 : "end",
14257         13 : "enter",
14258         27 : "esc",
14259         9  : "tab"
14260     },
14261
14262         /**
14263          * Enable this KeyNav
14264          */
14265         enable: function(){
14266                 if(this.disabled){
14267             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14268             // the EventObject will normalize Safari automatically
14269             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14270                 this.el.on("keydown", this.relay,  this);
14271             }else{
14272                 this.el.on("keydown", this.prepareEvent,  this);
14273                 this.el.on("keypress", this.relay,  this);
14274             }
14275                     this.disabled = false;
14276                 }
14277         },
14278
14279         /**
14280          * Disable this KeyNav
14281          */
14282         disable: function(){
14283                 if(!this.disabled){
14284                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14285                 this.el.un("keydown", this.relay);
14286             }else{
14287                 this.el.un("keydown", this.prepareEvent);
14288                 this.el.un("keypress", this.relay);
14289             }
14290                     this.disabled = true;
14291                 }
14292         }
14293 };/*
14294  * Based on:
14295  * Ext JS Library 1.1.1
14296  * Copyright(c) 2006-2007, Ext JS, LLC.
14297  *
14298  * Originally Released Under LGPL - original licence link has changed is not relivant.
14299  *
14300  * Fork - LGPL
14301  * <script type="text/javascript">
14302  */
14303
14304  
14305 /**
14306  * @class Roo.KeyMap
14307  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14308  * The constructor accepts the same config object as defined by {@link #addBinding}.
14309  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14310  * combination it will call the function with this signature (if the match is a multi-key
14311  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14312  * A KeyMap can also handle a string representation of keys.<br />
14313  * Usage:
14314  <pre><code>
14315 // map one key by key code
14316 var map = new Roo.KeyMap("my-element", {
14317     key: 13, // or Roo.EventObject.ENTER
14318     fn: myHandler,
14319     scope: myObject
14320 });
14321
14322 // map multiple keys to one action by string
14323 var map = new Roo.KeyMap("my-element", {
14324     key: "a\r\n\t",
14325     fn: myHandler,
14326     scope: myObject
14327 });
14328
14329 // map multiple keys to multiple actions by strings and array of codes
14330 var map = new Roo.KeyMap("my-element", [
14331     {
14332         key: [10,13],
14333         fn: function(){ alert("Return was pressed"); }
14334     }, {
14335         key: "abc",
14336         fn: function(){ alert('a, b or c was pressed'); }
14337     }, {
14338         key: "\t",
14339         ctrl:true,
14340         shift:true,
14341         fn: function(){ alert('Control + shift + tab was pressed.'); }
14342     }
14343 ]);
14344 </code></pre>
14345  * <b>Note: A KeyMap starts enabled</b>
14346  * @constructor
14347  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14348  * @param {Object} config The config (see {@link #addBinding})
14349  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14350  */
14351 Roo.KeyMap = function(el, config, eventName){
14352     this.el  = Roo.get(el);
14353     this.eventName = eventName || "keydown";
14354     this.bindings = [];
14355     if(config){
14356         this.addBinding(config);
14357     }
14358     this.enable();
14359 };
14360
14361 Roo.KeyMap.prototype = {
14362     /**
14363      * True to stop the event from bubbling and prevent the default browser action if the
14364      * key was handled by the KeyMap (defaults to false)
14365      * @type Boolean
14366      */
14367     stopEvent : false,
14368
14369     /**
14370      * Add a new binding to this KeyMap. The following config object properties are supported:
14371      * <pre>
14372 Property    Type             Description
14373 ----------  ---------------  ----------------------------------------------------------------------
14374 key         String/Array     A single keycode or an array of keycodes to handle
14375 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14376 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14377 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14378 fn          Function         The function to call when KeyMap finds the expected key combination
14379 scope       Object           The scope of the callback function
14380 </pre>
14381      *
14382      * Usage:
14383      * <pre><code>
14384 // Create a KeyMap
14385 var map = new Roo.KeyMap(document, {
14386     key: Roo.EventObject.ENTER,
14387     fn: handleKey,
14388     scope: this
14389 });
14390
14391 //Add a new binding to the existing KeyMap later
14392 map.addBinding({
14393     key: 'abc',
14394     shift: true,
14395     fn: handleKey,
14396     scope: this
14397 });
14398 </code></pre>
14399      * @param {Object/Array} config A single KeyMap config or an array of configs
14400      */
14401         addBinding : function(config){
14402         if(config instanceof Array){
14403             for(var i = 0, len = config.length; i < len; i++){
14404                 this.addBinding(config[i]);
14405             }
14406             return;
14407         }
14408         var keyCode = config.key,
14409             shift = config.shift, 
14410             ctrl = config.ctrl, 
14411             alt = config.alt,
14412             fn = config.fn,
14413             scope = config.scope;
14414         if(typeof keyCode == "string"){
14415             var ks = [];
14416             var keyString = keyCode.toUpperCase();
14417             for(var j = 0, len = keyString.length; j < len; j++){
14418                 ks.push(keyString.charCodeAt(j));
14419             }
14420             keyCode = ks;
14421         }
14422         var keyArray = keyCode instanceof Array;
14423         var handler = function(e){
14424             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14425                 var k = e.getKey();
14426                 if(keyArray){
14427                     for(var i = 0, len = keyCode.length; i < len; i++){
14428                         if(keyCode[i] == k){
14429                           if(this.stopEvent){
14430                               e.stopEvent();
14431                           }
14432                           fn.call(scope || window, k, e);
14433                           return;
14434                         }
14435                     }
14436                 }else{
14437                     if(k == keyCode){
14438                         if(this.stopEvent){
14439                            e.stopEvent();
14440                         }
14441                         fn.call(scope || window, k, e);
14442                     }
14443                 }
14444             }
14445         };
14446         this.bindings.push(handler);  
14447         },
14448
14449     /**
14450      * Shorthand for adding a single key listener
14451      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14452      * following options:
14453      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14454      * @param {Function} fn The function to call
14455      * @param {Object} scope (optional) The scope of the function
14456      */
14457     on : function(key, fn, scope){
14458         var keyCode, shift, ctrl, alt;
14459         if(typeof key == "object" && !(key instanceof Array)){
14460             keyCode = key.key;
14461             shift = key.shift;
14462             ctrl = key.ctrl;
14463             alt = key.alt;
14464         }else{
14465             keyCode = key;
14466         }
14467         this.addBinding({
14468             key: keyCode,
14469             shift: shift,
14470             ctrl: ctrl,
14471             alt: alt,
14472             fn: fn,
14473             scope: scope
14474         })
14475     },
14476
14477     // private
14478     handleKeyDown : function(e){
14479             if(this.enabled){ //just in case
14480             var b = this.bindings;
14481             for(var i = 0, len = b.length; i < len; i++){
14482                 b[i].call(this, e);
14483             }
14484             }
14485         },
14486         
14487         /**
14488          * Returns true if this KeyMap is enabled
14489          * @return {Boolean} 
14490          */
14491         isEnabled : function(){
14492             return this.enabled;  
14493         },
14494         
14495         /**
14496          * Enables this KeyMap
14497          */
14498         enable: function(){
14499                 if(!this.enabled){
14500                     this.el.on(this.eventName, this.handleKeyDown, this);
14501                     this.enabled = true;
14502                 }
14503         },
14504
14505         /**
14506          * Disable this KeyMap
14507          */
14508         disable: function(){
14509                 if(this.enabled){
14510                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14511                     this.enabled = false;
14512                 }
14513         }
14514 };/*
14515  * Based on:
14516  * Ext JS Library 1.1.1
14517  * Copyright(c) 2006-2007, Ext JS, LLC.
14518  *
14519  * Originally Released Under LGPL - original licence link has changed is not relivant.
14520  *
14521  * Fork - LGPL
14522  * <script type="text/javascript">
14523  */
14524
14525  
14526 /**
14527  * @class Roo.util.TextMetrics
14528  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14529  * wide, in pixels, a given block of text will be.
14530  * @singleton
14531  */
14532 Roo.util.TextMetrics = function(){
14533     var shared;
14534     return {
14535         /**
14536          * Measures the size of the specified text
14537          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14538          * that can affect the size of the rendered text
14539          * @param {String} text The text to measure
14540          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14541          * in order to accurately measure the text height
14542          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14543          */
14544         measure : function(el, text, fixedWidth){
14545             if(!shared){
14546                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14547             }
14548             shared.bind(el);
14549             shared.setFixedWidth(fixedWidth || 'auto');
14550             return shared.getSize(text);
14551         },
14552
14553         /**
14554          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14555          * the overhead of multiple calls to initialize the style properties on each measurement.
14556          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14557          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14558          * in order to accurately measure the text height
14559          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14560          */
14561         createInstance : function(el, fixedWidth){
14562             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14563         }
14564     };
14565 }();
14566
14567  
14568
14569 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14570     var ml = new Roo.Element(document.createElement('div'));
14571     document.body.appendChild(ml.dom);
14572     ml.position('absolute');
14573     ml.setLeftTop(-1000, -1000);
14574     ml.hide();
14575
14576     if(fixedWidth){
14577         ml.setWidth(fixedWidth);
14578     }
14579      
14580     var instance = {
14581         /**
14582          * Returns the size of the specified text based on the internal element's style and width properties
14583          * @memberOf Roo.util.TextMetrics.Instance#
14584          * @param {String} text The text to measure
14585          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14586          */
14587         getSize : function(text){
14588             ml.update(text);
14589             var s = ml.getSize();
14590             ml.update('');
14591             return s;
14592         },
14593
14594         /**
14595          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14596          * that can affect the size of the rendered text
14597          * @memberOf Roo.util.TextMetrics.Instance#
14598          * @param {String/HTMLElement} el The element, dom node or id
14599          */
14600         bind : function(el){
14601             ml.setStyle(
14602                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14603             );
14604         },
14605
14606         /**
14607          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14608          * to set a fixed width in order to accurately measure the text height.
14609          * @memberOf Roo.util.TextMetrics.Instance#
14610          * @param {Number} width The width to set on the element
14611          */
14612         setFixedWidth : function(width){
14613             ml.setWidth(width);
14614         },
14615
14616         /**
14617          * Returns the measured width of the specified text
14618          * @memberOf Roo.util.TextMetrics.Instance#
14619          * @param {String} text The text to measure
14620          * @return {Number} width The width in pixels
14621          */
14622         getWidth : function(text){
14623             ml.dom.style.width = 'auto';
14624             return this.getSize(text).width;
14625         },
14626
14627         /**
14628          * Returns the measured height of the specified text.  For multiline text, be sure to call
14629          * {@link #setFixedWidth} if necessary.
14630          * @memberOf Roo.util.TextMetrics.Instance#
14631          * @param {String} text The text to measure
14632          * @return {Number} height The height in pixels
14633          */
14634         getHeight : function(text){
14635             return this.getSize(text).height;
14636         }
14637     };
14638
14639     instance.bind(bindTo);
14640
14641     return instance;
14642 };
14643
14644 // backwards compat
14645 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14646  * Based on:
14647  * Ext JS Library 1.1.1
14648  * Copyright(c) 2006-2007, Ext JS, LLC.
14649  *
14650  * Originally Released Under LGPL - original licence link has changed is not relivant.
14651  *
14652  * Fork - LGPL
14653  * <script type="text/javascript">
14654  */
14655
14656 /**
14657  * @class Roo.state.Provider
14658  * Abstract base class for state provider implementations. This class provides methods
14659  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14660  * Provider interface.
14661  */
14662 Roo.state.Provider = function(){
14663     /**
14664      * @event statechange
14665      * Fires when a state change occurs.
14666      * @param {Provider} this This state provider
14667      * @param {String} key The state key which was changed
14668      * @param {String} value The encoded value for the state
14669      */
14670     this.addEvents({
14671         "statechange": true
14672     });
14673     this.state = {};
14674     Roo.state.Provider.superclass.constructor.call(this);
14675 };
14676 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14677     /**
14678      * Returns the current value for a key
14679      * @param {String} name The key name
14680      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14681      * @return {Mixed} The state data
14682      */
14683     get : function(name, defaultValue){
14684         return typeof this.state[name] == "undefined" ?
14685             defaultValue : this.state[name];
14686     },
14687     
14688     /**
14689      * Clears a value from the state
14690      * @param {String} name The key name
14691      */
14692     clear : function(name){
14693         delete this.state[name];
14694         this.fireEvent("statechange", this, name, null);
14695     },
14696     
14697     /**
14698      * Sets the value for a key
14699      * @param {String} name The key name
14700      * @param {Mixed} value The value to set
14701      */
14702     set : function(name, value){
14703         this.state[name] = value;
14704         this.fireEvent("statechange", this, name, value);
14705     },
14706     
14707     /**
14708      * Decodes a string previously encoded with {@link #encodeValue}.
14709      * @param {String} value The value to decode
14710      * @return {Mixed} The decoded value
14711      */
14712     decodeValue : function(cookie){
14713         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14714         var matches = re.exec(unescape(cookie));
14715         if(!matches || !matches[1]) return; // non state cookie
14716         var type = matches[1];
14717         var v = matches[2];
14718         switch(type){
14719             case "n":
14720                 return parseFloat(v);
14721             case "d":
14722                 return new Date(Date.parse(v));
14723             case "b":
14724                 return (v == "1");
14725             case "a":
14726                 var all = [];
14727                 var values = v.split("^");
14728                 for(var i = 0, len = values.length; i < len; i++){
14729                     all.push(this.decodeValue(values[i]));
14730                 }
14731                 return all;
14732            case "o":
14733                 var all = {};
14734                 var values = v.split("^");
14735                 for(var i = 0, len = values.length; i < len; i++){
14736                     var kv = values[i].split("=");
14737                     all[kv[0]] = this.decodeValue(kv[1]);
14738                 }
14739                 return all;
14740            default:
14741                 return v;
14742         }
14743     },
14744     
14745     /**
14746      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14747      * @param {Mixed} value The value to encode
14748      * @return {String} The encoded value
14749      */
14750     encodeValue : function(v){
14751         var enc;
14752         if(typeof v == "number"){
14753             enc = "n:" + v;
14754         }else if(typeof v == "boolean"){
14755             enc = "b:" + (v ? "1" : "0");
14756         }else if(v instanceof Date){
14757             enc = "d:" + v.toGMTString();
14758         }else if(v instanceof Array){
14759             var flat = "";
14760             for(var i = 0, len = v.length; i < len; i++){
14761                 flat += this.encodeValue(v[i]);
14762                 if(i != len-1) flat += "^";
14763             }
14764             enc = "a:" + flat;
14765         }else if(typeof v == "object"){
14766             var flat = "";
14767             for(var key in v){
14768                 if(typeof v[key] != "function"){
14769                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14770                 }
14771             }
14772             enc = "o:" + flat.substring(0, flat.length-1);
14773         }else{
14774             enc = "s:" + v;
14775         }
14776         return escape(enc);        
14777     }
14778 });
14779
14780 /*
14781  * Based on:
14782  * Ext JS Library 1.1.1
14783  * Copyright(c) 2006-2007, Ext JS, LLC.
14784  *
14785  * Originally Released Under LGPL - original licence link has changed is not relivant.
14786  *
14787  * Fork - LGPL
14788  * <script type="text/javascript">
14789  */
14790 /**
14791  * @class Roo.state.Manager
14792  * This is the global state manager. By default all components that are "state aware" check this class
14793  * for state information if you don't pass them a custom state provider. In order for this class
14794  * to be useful, it must be initialized with a provider when your application initializes.
14795  <pre><code>
14796 // in your initialization function
14797 init : function(){
14798    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14799    ...
14800    // supposed you have a {@link Roo.BorderLayout}
14801    var layout = new Roo.BorderLayout(...);
14802    layout.restoreState();
14803    // or a {Roo.BasicDialog}
14804    var dialog = new Roo.BasicDialog(...);
14805    dialog.restoreState();
14806  </code></pre>
14807  * @singleton
14808  */
14809 Roo.state.Manager = function(){
14810     var provider = new Roo.state.Provider();
14811     
14812     return {
14813         /**
14814          * Configures the default state provider for your application
14815          * @param {Provider} stateProvider The state provider to set
14816          */
14817         setProvider : function(stateProvider){
14818             provider = stateProvider;
14819         },
14820         
14821         /**
14822          * Returns the current value for a key
14823          * @param {String} name The key name
14824          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14825          * @return {Mixed} The state data
14826          */
14827         get : function(key, defaultValue){
14828             return provider.get(key, defaultValue);
14829         },
14830         
14831         /**
14832          * Sets the value for a key
14833          * @param {String} name The key name
14834          * @param {Mixed} value The state data
14835          */
14836          set : function(key, value){
14837             provider.set(key, value);
14838         },
14839         
14840         /**
14841          * Clears a value from the state
14842          * @param {String} name The key name
14843          */
14844         clear : function(key){
14845             provider.clear(key);
14846         },
14847         
14848         /**
14849          * Gets the currently configured state provider
14850          * @return {Provider} The state provider
14851          */
14852         getProvider : function(){
14853             return provider;
14854         }
14855     };
14856 }();
14857 /*
14858  * Based on:
14859  * Ext JS Library 1.1.1
14860  * Copyright(c) 2006-2007, Ext JS, LLC.
14861  *
14862  * Originally Released Under LGPL - original licence link has changed is not relivant.
14863  *
14864  * Fork - LGPL
14865  * <script type="text/javascript">
14866  */
14867 /**
14868  * @class Roo.state.CookieProvider
14869  * @extends Roo.state.Provider
14870  * The default Provider implementation which saves state via cookies.
14871  * <br />Usage:
14872  <pre><code>
14873    var cp = new Roo.state.CookieProvider({
14874        path: "/cgi-bin/",
14875        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14876        domain: "roojs.com"
14877    })
14878    Roo.state.Manager.setProvider(cp);
14879  </code></pre>
14880  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14881  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14882  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14883  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14884  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14885  * domain the page is running on including the 'www' like 'www.roojs.com')
14886  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14887  * @constructor
14888  * Create a new CookieProvider
14889  * @param {Object} config The configuration object
14890  */
14891 Roo.state.CookieProvider = function(config){
14892     Roo.state.CookieProvider.superclass.constructor.call(this);
14893     this.path = "/";
14894     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14895     this.domain = null;
14896     this.secure = false;
14897     Roo.apply(this, config);
14898     this.state = this.readCookies();
14899 };
14900
14901 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14902     // private
14903     set : function(name, value){
14904         if(typeof value == "undefined" || value === null){
14905             this.clear(name);
14906             return;
14907         }
14908         this.setCookie(name, value);
14909         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14910     },
14911
14912     // private
14913     clear : function(name){
14914         this.clearCookie(name);
14915         Roo.state.CookieProvider.superclass.clear.call(this, name);
14916     },
14917
14918     // private
14919     readCookies : function(){
14920         var cookies = {};
14921         var c = document.cookie + ";";
14922         var re = /\s?(.*?)=(.*?);/g;
14923         var matches;
14924         while((matches = re.exec(c)) != null){
14925             var name = matches[1];
14926             var value = matches[2];
14927             if(name && name.substring(0,3) == "ys-"){
14928                 cookies[name.substr(3)] = this.decodeValue(value);
14929             }
14930         }
14931         return cookies;
14932     },
14933
14934     // private
14935     setCookie : function(name, value){
14936         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14937            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14938            ((this.path == null) ? "" : ("; path=" + this.path)) +
14939            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14940            ((this.secure == true) ? "; secure" : "");
14941     },
14942
14943     // private
14944     clearCookie : function(name){
14945         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14946            ((this.path == null) ? "" : ("; path=" + this.path)) +
14947            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14948            ((this.secure == true) ? "; secure" : "");
14949     }
14950 });