roojs-all.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618
619         /**
620          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621          * you may want to set this to true.
622          * @type Boolean
623          */
624         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
625         
626         
627                 
628         /**
629          * Selects a single element as a Roo Element
630          * This is about as close as you can get to jQuery's $('do crazy stuff')
631          * @param {String} selector The selector/xpath query
632          * @param {Node} root (optional) The start of the query (defaults to document).
633          * @return {Roo.Element}
634          */
635         selectNode : function(selector, root) 
636         {
637             var node = Roo.DomQuery.selectNode(selector,root);
638             return node ? Roo.get(node) : new Roo.Element(false);
639         }
640         
641     });
642
643
644 })();
645
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
648 /*
649  * Based on:
650  * Ext JS Library 1.1.1
651  * Copyright(c) 2006-2007, Ext JS, LLC.
652  *
653  * Originally Released Under LGPL - original licence link has changed is not relivant.
654  *
655  * Fork - LGPL
656  * <script type="text/javascript">
657  */
658
659 (function() {    
660     // wrappedn so fnCleanup is not in global scope...
661     if(Roo.isIE) {
662         function fnCleanUp() {
663             var p = Function.prototype;
664             delete p.createSequence;
665             delete p.defer;
666             delete p.createDelegate;
667             delete p.createCallback;
668             delete p.createInterceptor;
669
670             window.detachEvent("onunload", fnCleanUp);
671         }
672         window.attachEvent("onunload", fnCleanUp);
673     }
674 })();
675
676
677 /**
678  * @class Function
679  * These functions are available on every Function object (any JavaScript function).
680  */
681 Roo.apply(Function.prototype, {
682      /**
683      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685      * Will create a function that is bound to those 2 args.
686      * @return {Function} The new function
687     */
688     createCallback : function(/*args...*/){
689         // make args available, in function below
690         var args = arguments;
691         var method = this;
692         return function() {
693             return method.apply(window, args);
694         };
695     },
696
697     /**
698      * Creates a delegate (callback) that sets the scope to obj.
699      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700      * Will create a function that is automatically scoped to this.
701      * @param {Object} obj (optional) The object for which the scope is set
702      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704      *                                             if a number the args are inserted at the specified position
705      * @return {Function} The new function
706      */
707     createDelegate : function(obj, args, appendArgs){
708         var method = this;
709         return function() {
710             var callArgs = args || arguments;
711             if(appendArgs === true){
712                 callArgs = Array.prototype.slice.call(arguments, 0);
713                 callArgs = callArgs.concat(args);
714             }else if(typeof appendArgs == "number"){
715                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
718             }
719             return method.apply(obj || window, callArgs);
720         };
721     },
722
723     /**
724      * Calls this function after the number of millseconds specified.
725      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726      * @param {Object} obj (optional) The object for which the scope is set
727      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729      *                                             if a number the args are inserted at the specified position
730      * @return {Number} The timeout id that can be used with clearTimeout
731      */
732     defer : function(millis, obj, args, appendArgs){
733         var fn = this.createDelegate(obj, args, appendArgs);
734         if(millis){
735             return setTimeout(fn, millis);
736         }
737         fn();
738         return 0;
739     },
740     /**
741      * Create a combined function call sequence of the original function + the passed function.
742      * The resulting function returns the results of the original function.
743      * The passed fcn is called with the parameters of the original function
744      * @param {Function} fcn The function to sequence
745      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746      * @return {Function} The new function
747      */
748     createSequence : function(fcn, scope){
749         if(typeof fcn != "function"){
750             return this;
751         }
752         var method = this;
753         return function() {
754             var retval = method.apply(this || window, arguments);
755             fcn.apply(scope || this || window, arguments);
756             return retval;
757         };
758     },
759
760     /**
761      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762      * The resulting function returns the results of the original function.
763      * The passed fcn is called with the parameters of the original function.
764      * @addon
765      * @param {Function} fcn The function to call before the original
766      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767      * @return {Function} The new function
768      */
769     createInterceptor : function(fcn, scope){
770         if(typeof fcn != "function"){
771             return this;
772         }
773         var method = this;
774         return function() {
775             fcn.target = this;
776             fcn.method = method;
777             if(fcn.apply(scope || this || window, arguments) === false){
778                 return;
779             }
780             return method.apply(this || window, arguments);
781         };
782     }
783 });
784 /*
785  * Based on:
786  * Ext JS Library 1.1.1
787  * Copyright(c) 2006-2007, Ext JS, LLC.
788  *
789  * Originally Released Under LGPL - original licence link has changed is not relivant.
790  *
791  * Fork - LGPL
792  * <script type="text/javascript">
793  */
794
795 Roo.applyIf(String, {
796     
797     /** @scope String */
798     
799     /**
800      * Escapes the passed string for ' and \
801      * @param {String} string The string to escape
802      * @return {String} The escaped string
803      * @static
804      */
805     escape : function(string) {
806         return string.replace(/('|\\)/g, "\\$1");
807     },
808
809     /**
810      * Pads the left side of a string with a specified character.  This is especially useful
811      * for normalizing number and date strings.  Example usage:
812      * <pre><code>
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
815 </code></pre>
816      * @param {String} string The original string
817      * @param {Number} size The total length of the output string
818      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819      * @return {String} The padded string
820      * @static
821      */
822     leftPad : function (val, size, ch) {
823         var result = new String(val);
824         if(ch === null || ch === undefined || ch === '') {
825             ch = " ";
826         }
827         while (result.length < size) {
828             result = ch + result;
829         }
830         return result;
831     },
832
833     /**
834      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
835      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
836      * <pre><code>
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
840 </code></pre>
841      * @param {String} string The tokenized string to be formatted
842      * @param {String} value1 The value to replace token {0}
843      * @param {String} value2 Etc...
844      * @return {String} The formatted string
845      * @static
846      */
847     format : function(format){
848         var args = Array.prototype.slice.call(arguments, 1);
849         return format.replace(/\{(\d+)\}/g, function(m, i){
850             return Roo.util.Format.htmlEncode(args[i]);
851         });
852     }
853 });
854
855 /**
856  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
857  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
858  * they are already different, the first value passed in is returned.  Note that this method returns the new value
859  * but does not change the current string.
860  * <pre><code>
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
863
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
866 </code></pre>
867  * @param {String} value The value to compare to the current string
868  * @param {String} other The new value to use if the string already equals the first value passed in
869  * @return {String} The new value
870  */
871  
872 String.prototype.toggle = function(value, other){
873     return this == value ? other : value;
874 };/*
875  * Based on:
876  * Ext JS Library 1.1.1
877  * Copyright(c) 2006-2007, Ext JS, LLC.
878  *
879  * Originally Released Under LGPL - original licence link has changed is not relivant.
880  *
881  * Fork - LGPL
882  * <script type="text/javascript">
883  */
884
885  /**
886  * @class Number
887  */
888 Roo.applyIf(Number.prototype, {
889     /**
890      * Checks whether or not the current number is within a desired range.  If the number is already within the
891      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892      * exceeded.  Note that this method returns the constrained value but does not change the current number.
893      * @param {Number} min The minimum number in the range
894      * @param {Number} max The maximum number in the range
895      * @return {Number} The constrained value if outside the range, otherwise the current value
896      */
897     constrain : function(min, max){
898         return Math.min(Math.max(this, min), max);
899     }
900 });/*
901  * Based on:
902  * Ext JS Library 1.1.1
903  * Copyright(c) 2006-2007, Ext JS, LLC.
904  *
905  * Originally Released Under LGPL - original licence link has changed is not relivant.
906  *
907  * Fork - LGPL
908  * <script type="text/javascript">
909  */
910  /**
911  * @class Array
912  */
913 Roo.applyIf(Array.prototype, {
914     /**
915      * Checks whether or not the specified object exists in the array.
916      * @param {Object} o The object to check for
917      * @return {Number} The index of o in the array (or -1 if it is not found)
918      */
919     indexOf : function(o){
920        for (var i = 0, len = this.length; i < len; i++){
921               if(this[i] == o) return i;
922        }
923            return -1;
924     },
925
926     /**
927      * Removes the specified object from the array.  If the object is not found nothing happens.
928      * @param {Object} o The object to remove
929      */
930     remove : function(o){
931        var index = this.indexOf(o);
932        if(index != -1){
933            this.splice(index, 1);
934        }
935     },
936     /**
937      * Map (JS 1.6 compatibility)
938      * @param {Function} function  to call
939      */
940     map : function(fun )
941     {
942         var len = this.length >>> 0;
943         if (typeof fun != "function")
944             throw new TypeError();
945
946         var res = new Array(len);
947         var thisp = arguments[1];
948         for (var i = 0; i < len; i++)
949         {
950             if (i in this)
951                 res[i] = fun.call(thisp, this[i], i, this);
952         }
953
954         return res;
955     }
956     
957 });
958
959
960  /*
961  * Based on:
962  * Ext JS Library 1.1.1
963  * Copyright(c) 2006-2007, Ext JS, LLC.
964  *
965  * Originally Released Under LGPL - original licence link has changed is not relivant.
966  *
967  * Fork - LGPL
968  * <script type="text/javascript">
969  */
970
971 /**
972  * @class Date
973  *
974  * The date parsing and format syntax is a subset of
975  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976  * supported will provide results equivalent to their PHP versions.
977  *
978  * Following is the list of all currently supported formats:
979  *<pre>
980 Sample date:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
982
983 Format  Output      Description
984 ------  ----------  --------------------------------------------------------------
985   d      10         Day of the month, 2 digits with leading zeros
986   D      Wed        A textual representation of a day, three letters
987   j      10         Day of the month without leading zeros
988   l      Wednesday  A full textual representation of the day of the week
989   S      th         English ordinal day of month suffix, 2 chars (use with j)
990   w      3          Numeric representation of the day of the week
991   z      9          The julian date, or day of the year (0-365)
992   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993   F      January    A full textual representation of the month
994   m      01         Numeric representation of a month, with leading zeros
995   M      Jan        Month name abbreviation, three letters
996   n      1          Numeric representation of a month, without leading zeros
997   t      31         Number of days in the given month
998   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
999   Y      2007       A full numeric representation of a year, 4 digits
1000   y      07         A two digit representation of a year
1001   a      pm         Lowercase Ante meridiem and Post meridiem
1002   A      PM         Uppercase Ante meridiem and Post meridiem
1003   g      3          12-hour format of an hour without leading zeros
1004   G      15         24-hour format of an hour without leading zeros
1005   h      03         12-hour format of an hour with leading zeros
1006   H      15         24-hour format of an hour with leading zeros
1007   i      05         Minutes with leading zeros
1008   s      01         Seconds, with leading zeros
1009   O      -0600      Difference to Greenwich time (GMT) in hours
1010   T      CST        Timezone setting of the machine running the code
1011   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1012 </pre>
1013  *
1014  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1015  * <pre><code>
1016 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1017 document.write(dt.format('Y-m-d'));                         //2007-01-10
1018 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1019 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
1020  </code></pre>
1021  *
1022  * Here are some standard date/time patterns that you might find helpful.  They
1023  * are not part of the source of Date.js, but to use them you can simply copy this
1024  * block of code into any script that is included after Date.js and they will also become
1025  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1026  * <pre><code>
1027 Date.patterns = {
1028     ISO8601Long:"Y-m-d H:i:s",
1029     ISO8601Short:"Y-m-d",
1030     ShortDate: "n/j/Y",
1031     LongDate: "l, F d, Y",
1032     FullDateTime: "l, F d, Y g:i:s A",
1033     MonthDay: "F d",
1034     ShortTime: "g:i A",
1035     LongTime: "g:i:s A",
1036     SortableDateTime: "Y-m-d\\TH:i:s",
1037     UniversalSortableDateTime: "Y-m-d H:i:sO",
1038     YearMonth: "F, Y"
1039 };
1040 </code></pre>
1041  *
1042  * Example usage:
1043  * <pre><code>
1044 var dt = new Date();
1045 document.write(dt.format(Date.patterns.ShortDate));
1046  </code></pre>
1047  */
1048
1049 /*
1050  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1051  * They generate precompiled functions from date formats instead of parsing and
1052  * processing the pattern every time you format a date.  These functions are available
1053  * on every Date object (any javascript function).
1054  *
1055  * The original article and download are here:
1056  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1057  *
1058  */
1059  
1060  
1061  // was in core
1062 /**
1063  Returns the number of milliseconds between this date and date
1064  @param {Date} date (optional) Defaults to now
1065  @return {Number} The diff in milliseconds
1066  @member Date getElapsed
1067  */
1068 Date.prototype.getElapsed = function(date) {
1069         return Math.abs((date || new Date()).getTime()-this.getTime());
1070 };
1071 // was in date file..
1072
1073
1074 // private
1075 Date.parseFunctions = {count:0};
1076 // private
1077 Date.parseRegexes = [];
1078 // private
1079 Date.formatFunctions = {count:0};
1080
1081 // private
1082 Date.prototype.dateFormat = function(format) {
1083     if (Date.formatFunctions[format] == null) {
1084         Date.createNewFormat(format);
1085     }
1086     var func = Date.formatFunctions[format];
1087     return this[func]();
1088 };
1089
1090
1091 /**
1092  * Formats a date given the supplied format string
1093  * @param {String} format The format string
1094  * @return {String} The formatted date
1095  * @method
1096  */
1097 Date.prototype.format = Date.prototype.dateFormat;
1098
1099 // private
1100 Date.createNewFormat = function(format) {
1101     var funcName = "format" + Date.formatFunctions.count++;
1102     Date.formatFunctions[format] = funcName;
1103     var code = "Date.prototype." + funcName + " = function(){return ";
1104     var special = false;
1105     var ch = '';
1106     for (var i = 0; i < format.length; ++i) {
1107         ch = format.charAt(i);
1108         if (!special && ch == "\\") {
1109             special = true;
1110         }
1111         else if (special) {
1112             special = false;
1113             code += "'" + String.escape(ch) + "' + ";
1114         }
1115         else {
1116             code += Date.getFormatCode(ch);
1117         }
1118     }
1119     /** eval:var:zzzzzzzzzzzzz */
1120     eval(code.substring(0, code.length - 3) + ";}");
1121 };
1122
1123 // private
1124 Date.getFormatCode = function(character) {
1125     switch (character) {
1126     case "d":
1127         return "String.leftPad(this.getDate(), 2, '0') + ";
1128     case "D":
1129         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1130     case "j":
1131         return "this.getDate() + ";
1132     case "l":
1133         return "Date.dayNames[this.getDay()] + ";
1134     case "S":
1135         return "this.getSuffix() + ";
1136     case "w":
1137         return "this.getDay() + ";
1138     case "z":
1139         return "this.getDayOfYear() + ";
1140     case "W":
1141         return "this.getWeekOfYear() + ";
1142     case "F":
1143         return "Date.monthNames[this.getMonth()] + ";
1144     case "m":
1145         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1146     case "M":
1147         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1148     case "n":
1149         return "(this.getMonth() + 1) + ";
1150     case "t":
1151         return "this.getDaysInMonth() + ";
1152     case "L":
1153         return "(this.isLeapYear() ? 1 : 0) + ";
1154     case "Y":
1155         return "this.getFullYear() + ";
1156     case "y":
1157         return "('' + this.getFullYear()).substring(2, 4) + ";
1158     case "a":
1159         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1160     case "A":
1161         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1162     case "g":
1163         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1164     case "G":
1165         return "this.getHours() + ";
1166     case "h":
1167         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1168     case "H":
1169         return "String.leftPad(this.getHours(), 2, '0') + ";
1170     case "i":
1171         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1172     case "s":
1173         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1174     case "O":
1175         return "this.getGMTOffset() + ";
1176     case "T":
1177         return "this.getTimezone() + ";
1178     case "Z":
1179         return "(this.getTimezoneOffset() * -60) + ";
1180     default:
1181         return "'" + String.escape(character) + "' + ";
1182     }
1183 };
1184
1185 /**
1186  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1187  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1188  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1189  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1190  * string or the parse operation will fail.
1191  * Example Usage:
1192 <pre><code>
1193 //dt = Fri May 25 2007 (current date)
1194 var dt = new Date();
1195
1196 //dt = Thu May 25 2006 (today's month/day in 2006)
1197 dt = Date.parseDate("2006", "Y");
1198
1199 //dt = Sun Jan 15 2006 (all date parts specified)
1200 dt = Date.parseDate("2006-1-15", "Y-m-d");
1201
1202 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1203 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1204 </code></pre>
1205  * @param {String} input The unparsed date as a string
1206  * @param {String} format The format the date is in
1207  * @return {Date} The parsed date
1208  * @static
1209  */
1210 Date.parseDate = function(input, format) {
1211     if (Date.parseFunctions[format] == null) {
1212         Date.createParser(format);
1213     }
1214     var func = Date.parseFunctions[format];
1215     return Date[func](input);
1216 };
1217 /**
1218  * @private
1219  */
1220 Date.createParser = function(format) {
1221     var funcName = "parse" + Date.parseFunctions.count++;
1222     var regexNum = Date.parseRegexes.length;
1223     var currentGroup = 1;
1224     Date.parseFunctions[format] = funcName;
1225
1226     var code = "Date." + funcName + " = function(input){\n"
1227         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1228         + "var d = new Date();\n"
1229         + "y = d.getFullYear();\n"
1230         + "m = d.getMonth();\n"
1231         + "d = d.getDate();\n"
1232         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1233         + "if (results && results.length > 0) {";
1234     var regex = "";
1235
1236     var special = false;
1237     var ch = '';
1238     for (var i = 0; i < format.length; ++i) {
1239         ch = format.charAt(i);
1240         if (!special && ch == "\\") {
1241             special = true;
1242         }
1243         else if (special) {
1244             special = false;
1245             regex += String.escape(ch);
1246         }
1247         else {
1248             var obj = Date.formatCodeToRegex(ch, currentGroup);
1249             currentGroup += obj.g;
1250             regex += obj.s;
1251             if (obj.g && obj.c) {
1252                 code += obj.c;
1253             }
1254         }
1255     }
1256
1257     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1258         + "{v = new Date(y, m, d, h, i, s);}\n"
1259         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1260         + "{v = new Date(y, m, d, h, i);}\n"
1261         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1262         + "{v = new Date(y, m, d, h);}\n"
1263         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1264         + "{v = new Date(y, m, d);}\n"
1265         + "else if (y >= 0 && m >= 0)\n"
1266         + "{v = new Date(y, m);}\n"
1267         + "else if (y >= 0)\n"
1268         + "{v = new Date(y);}\n"
1269         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1270         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1271         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1272         + ";}";
1273
1274     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1275     /** eval:var:zzzzzzzzzzzzz */
1276     eval(code);
1277 };
1278
1279 // private
1280 Date.formatCodeToRegex = function(character, currentGroup) {
1281     switch (character) {
1282     case "D":
1283         return {g:0,
1284         c:null,
1285         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1286     case "j":
1287         return {g:1,
1288             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1289             s:"(\\d{1,2})"}; // day of month without leading zeroes
1290     case "d":
1291         return {g:1,
1292             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1293             s:"(\\d{2})"}; // day of month with leading zeroes
1294     case "l":
1295         return {g:0,
1296             c:null,
1297             s:"(?:" + Date.dayNames.join("|") + ")"};
1298     case "S":
1299         return {g:0,
1300             c:null,
1301             s:"(?:st|nd|rd|th)"};
1302     case "w":
1303         return {g:0,
1304             c:null,
1305             s:"\\d"};
1306     case "z":
1307         return {g:0,
1308             c:null,
1309             s:"(?:\\d{1,3})"};
1310     case "W":
1311         return {g:0,
1312             c:null,
1313             s:"(?:\\d{2})"};
1314     case "F":
1315         return {g:1,
1316             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1317             s:"(" + Date.monthNames.join("|") + ")"};
1318     case "M":
1319         return {g:1,
1320             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1321             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1322     case "n":
1323         return {g:1,
1324             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1325             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1326     case "m":
1327         return {g:1,
1328             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1329             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1330     case "t":
1331         return {g:0,
1332             c:null,
1333             s:"\\d{1,2}"};
1334     case "L":
1335         return {g:0,
1336             c:null,
1337             s:"(?:1|0)"};
1338     case "Y":
1339         return {g:1,
1340             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1341             s:"(\\d{4})"};
1342     case "y":
1343         return {g:1,
1344             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1345                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1346             s:"(\\d{1,2})"};
1347     case "a":
1348         return {g:1,
1349             c:"if (results[" + currentGroup + "] == 'am') {\n"
1350                 + "if (h == 12) { h = 0; }\n"
1351                 + "} else { if (h < 12) { h += 12; }}",
1352             s:"(am|pm)"};
1353     case "A":
1354         return {g:1,
1355             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1356                 + "if (h == 12) { h = 0; }\n"
1357                 + "} else { if (h < 12) { h += 12; }}",
1358             s:"(AM|PM)"};
1359     case "g":
1360     case "G":
1361         return {g:1,
1362             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1363             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1364     case "h":
1365     case "H":
1366         return {g:1,
1367             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1369     case "i":
1370         return {g:1,
1371             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1372             s:"(\\d{2})"};
1373     case "s":
1374         return {g:1,
1375             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1376             s:"(\\d{2})"};
1377     case "O":
1378         return {g:1,
1379             c:[
1380                 "o = results[", currentGroup, "];\n",
1381                 "var sn = o.substring(0,1);\n", // get + / - sign
1382                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1383                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1384                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1385                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1386             ].join(""),
1387             s:"([+\-]\\d{4})"};
1388     case "T":
1389         return {g:0,
1390             c:null,
1391             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1392     case "Z":
1393         return {g:1,
1394             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1395                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1396             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1397     default:
1398         return {g:0,
1399             c:null,
1400             s:String.escape(character)};
1401     }
1402 };
1403
1404 /**
1405  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1406  * @return {String} The abbreviated timezone name (e.g. 'CST')
1407  */
1408 Date.prototype.getTimezone = function() {
1409     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1410 };
1411
1412 /**
1413  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1414  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1415  */
1416 Date.prototype.getGMTOffset = function() {
1417     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1418         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1419         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1420 };
1421
1422 /**
1423  * Get the numeric day number of the year, adjusted for leap year.
1424  * @return {Number} 0 through 364 (365 in leap years)
1425  */
1426 Date.prototype.getDayOfYear = function() {
1427     var num = 0;
1428     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1429     for (var i = 0; i < this.getMonth(); ++i) {
1430         num += Date.daysInMonth[i];
1431     }
1432     return num + this.getDate() - 1;
1433 };
1434
1435 /**
1436  * Get the string representation of the numeric week number of the year
1437  * (equivalent to the format specifier 'W').
1438  * @return {String} '00' through '52'
1439  */
1440 Date.prototype.getWeekOfYear = function() {
1441     // Skip to Thursday of this week
1442     var now = this.getDayOfYear() + (4 - this.getDay());
1443     // Find the first Thursday of the year
1444     var jan1 = new Date(this.getFullYear(), 0, 1);
1445     var then = (7 - jan1.getDay() + 4);
1446     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1447 };
1448
1449 /**
1450  * Whether or not the current date is in a leap year.
1451  * @return {Boolean} True if the current date is in a leap year, else false
1452  */
1453 Date.prototype.isLeapYear = function() {
1454     var year = this.getFullYear();
1455     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1456 };
1457
1458 /**
1459  * Get the first day of the current month, adjusted for leap year.  The returned value
1460  * is the numeric day index within the week (0-6) which can be used in conjunction with
1461  * the {@link #monthNames} array to retrieve the textual day name.
1462  * Example:
1463  *<pre><code>
1464 var dt = new Date('1/10/2007');
1465 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1466 </code></pre>
1467  * @return {Number} The day number (0-6)
1468  */
1469 Date.prototype.getFirstDayOfMonth = function() {
1470     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1471     return (day < 0) ? (day + 7) : day;
1472 };
1473
1474 /**
1475  * Get the last day of the current month, adjusted for leap year.  The returned value
1476  * is the numeric day index within the week (0-6) which can be used in conjunction with
1477  * the {@link #monthNames} array to retrieve the textual day name.
1478  * Example:
1479  *<pre><code>
1480 var dt = new Date('1/10/2007');
1481 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1482 </code></pre>
1483  * @return {Number} The day number (0-6)
1484  */
1485 Date.prototype.getLastDayOfMonth = function() {
1486     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1487     return (day < 0) ? (day + 7) : day;
1488 };
1489
1490
1491 /**
1492  * Get the first date of this date's month
1493  * @return {Date}
1494  */
1495 Date.prototype.getFirstDateOfMonth = function() {
1496     return new Date(this.getFullYear(), this.getMonth(), 1);
1497 };
1498
1499 /**
1500  * Get the last date of this date's month
1501  * @return {Date}
1502  */
1503 Date.prototype.getLastDateOfMonth = function() {
1504     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1505 };
1506 /**
1507  * Get the number of days in the current month, adjusted for leap year.
1508  * @return {Number} The number of days in the month
1509  */
1510 Date.prototype.getDaysInMonth = function() {
1511     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1512     return Date.daysInMonth[this.getMonth()];
1513 };
1514
1515 /**
1516  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1517  * @return {String} 'st, 'nd', 'rd' or 'th'
1518  */
1519 Date.prototype.getSuffix = function() {
1520     switch (this.getDate()) {
1521         case 1:
1522         case 21:
1523         case 31:
1524             return "st";
1525         case 2:
1526         case 22:
1527             return "nd";
1528         case 3:
1529         case 23:
1530             return "rd";
1531         default:
1532             return "th";
1533     }
1534 };
1535
1536 // private
1537 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1538
1539 /**
1540  * An array of textual month names.
1541  * Override these values for international dates, for example...
1542  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1543  * @type Array
1544  * @static
1545  */
1546 Date.monthNames =
1547    ["January",
1548     "February",
1549     "March",
1550     "April",
1551     "May",
1552     "June",
1553     "July",
1554     "August",
1555     "September",
1556     "October",
1557     "November",
1558     "December"];
1559
1560 /**
1561  * An array of textual day names.
1562  * Override these values for international dates, for example...
1563  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1564  * @type Array
1565  * @static
1566  */
1567 Date.dayNames =
1568    ["Sunday",
1569     "Monday",
1570     "Tuesday",
1571     "Wednesday",
1572     "Thursday",
1573     "Friday",
1574     "Saturday"];
1575
1576 // private
1577 Date.y2kYear = 50;
1578 // private
1579 Date.monthNumbers = {
1580     Jan:0,
1581     Feb:1,
1582     Mar:2,
1583     Apr:3,
1584     May:4,
1585     Jun:5,
1586     Jul:6,
1587     Aug:7,
1588     Sep:8,
1589     Oct:9,
1590     Nov:10,
1591     Dec:11};
1592
1593 /**
1594  * Creates and returns a new Date instance with the exact same date value as the called instance.
1595  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1596  * variable will also be changed.  When the intention is to create a new variable that will not
1597  * modify the original instance, you should create a clone.
1598  *
1599  * Example of correctly cloning a date:
1600  * <pre><code>
1601 //wrong way:
1602 var orig = new Date('10/1/2006');
1603 var copy = orig;
1604 copy.setDate(5);
1605 document.write(orig);  //returns 'Thu Oct 05 2006'!
1606
1607 //correct way:
1608 var orig = new Date('10/1/2006');
1609 var copy = orig.clone();
1610 copy.setDate(5);
1611 document.write(orig);  //returns 'Thu Oct 01 2006'
1612 </code></pre>
1613  * @return {Date} The new Date instance
1614  */
1615 Date.prototype.clone = function() {
1616         return new Date(this.getTime());
1617 };
1618
1619 /**
1620  * Clears any time information from this date
1621  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1622  @return {Date} this or the clone
1623  */
1624 Date.prototype.clearTime = function(clone){
1625     if(clone){
1626         return this.clone().clearTime();
1627     }
1628     this.setHours(0);
1629     this.setMinutes(0);
1630     this.setSeconds(0);
1631     this.setMilliseconds(0);
1632     return this;
1633 };
1634
1635 // private
1636 // safari setMonth is broken
1637 if(Roo.isSafari){
1638     Date.brokenSetMonth = Date.prototype.setMonth;
1639         Date.prototype.setMonth = function(num){
1640                 if(num <= -1){
1641                         var n = Math.ceil(-num);
1642                         var back_year = Math.ceil(n/12);
1643                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1644                         this.setFullYear(this.getFullYear() - back_year);
1645                         return Date.brokenSetMonth.call(this, month);
1646                 } else {
1647                         return Date.brokenSetMonth.apply(this, arguments);
1648                 }
1649         };
1650 }
1651
1652 /** Date interval constant 
1653 * @static 
1654 * @type String */
1655 Date.MILLI = "ms";
1656 /** Date interval constant 
1657 * @static 
1658 * @type String */
1659 Date.SECOND = "s";
1660 /** Date interval constant 
1661 * @static 
1662 * @type String */
1663 Date.MINUTE = "mi";
1664 /** Date interval constant 
1665 * @static 
1666 * @type String */
1667 Date.HOUR = "h";
1668 /** Date interval constant 
1669 * @static 
1670 * @type String */
1671 Date.DAY = "d";
1672 /** Date interval constant 
1673 * @static 
1674 * @type String */
1675 Date.MONTH = "mo";
1676 /** Date interval constant 
1677 * @static 
1678 * @type String */
1679 Date.YEAR = "y";
1680
1681 /**
1682  * Provides a convenient method of performing basic date arithmetic.  This method
1683  * does not modify the Date instance being called - it creates and returns
1684  * a new Date instance containing the resulting date value.
1685  *
1686  * Examples:
1687  * <pre><code>
1688 //Basic usage:
1689 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1690 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1691
1692 //Negative values will subtract correctly:
1693 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1694 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1695
1696 //You can even chain several calls together in one line!
1697 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1698 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1699  </code></pre>
1700  *
1701  * @param {String} interval   A valid date interval enum value
1702  * @param {Number} value      The amount to add to the current date
1703  * @return {Date} The new Date instance
1704  */
1705 Date.prototype.add = function(interval, value){
1706   var d = this.clone();
1707   if (!interval || value === 0) return d;
1708   switch(interval.toLowerCase()){
1709     case Date.MILLI:
1710       d.setMilliseconds(this.getMilliseconds() + value);
1711       break;
1712     case Date.SECOND:
1713       d.setSeconds(this.getSeconds() + value);
1714       break;
1715     case Date.MINUTE:
1716       d.setMinutes(this.getMinutes() + value);
1717       break;
1718     case Date.HOUR:
1719       d.setHours(this.getHours() + value);
1720       break;
1721     case Date.DAY:
1722       d.setDate(this.getDate() + value);
1723       break;
1724     case Date.MONTH:
1725       var day = this.getDate();
1726       if(day > 28){
1727           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1728       }
1729       d.setDate(day);
1730       d.setMonth(this.getMonth() + value);
1731       break;
1732     case Date.YEAR:
1733       d.setFullYear(this.getFullYear() + value);
1734       break;
1735   }
1736   return d;
1737 };/*
1738  * Based on:
1739  * Ext JS Library 1.1.1
1740  * Copyright(c) 2006-2007, Ext JS, LLC.
1741  *
1742  * Originally Released Under LGPL - original licence link has changed is not relivant.
1743  *
1744  * Fork - LGPL
1745  * <script type="text/javascript">
1746  */
1747
1748 Roo.lib.Dom = {
1749     getViewWidth : function(full) {
1750         return full ? this.getDocumentWidth() : this.getViewportWidth();
1751     },
1752
1753     getViewHeight : function(full) {
1754         return full ? this.getDocumentHeight() : this.getViewportHeight();
1755     },
1756
1757     getDocumentHeight: function() {
1758         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1759         return Math.max(scrollHeight, this.getViewportHeight());
1760     },
1761
1762     getDocumentWidth: function() {
1763         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1764         return Math.max(scrollWidth, this.getViewportWidth());
1765     },
1766
1767     getViewportHeight: function() {
1768         var height = self.innerHeight;
1769         var mode = document.compatMode;
1770
1771         if ((mode || Roo.isIE) && !Roo.isOpera) {
1772             height = (mode == "CSS1Compat") ?
1773                      document.documentElement.clientHeight :
1774                      document.body.clientHeight;
1775         }
1776
1777         return height;
1778     },
1779
1780     getViewportWidth: function() {
1781         var width = self.innerWidth;
1782         var mode = document.compatMode;
1783
1784         if (mode || Roo.isIE) {
1785             width = (mode == "CSS1Compat") ?
1786                     document.documentElement.clientWidth :
1787                     document.body.clientWidth;
1788         }
1789         return width;
1790     },
1791
1792     isAncestor : function(p, c) {
1793         p = Roo.getDom(p);
1794         c = Roo.getDom(c);
1795         if (!p || !c) {
1796             return false;
1797         }
1798
1799         if (p.contains && !Roo.isSafari) {
1800             return p.contains(c);
1801         } else if (p.compareDocumentPosition) {
1802             return !!(p.compareDocumentPosition(c) & 16);
1803         } else {
1804             var parent = c.parentNode;
1805             while (parent) {
1806                 if (parent == p) {
1807                     return true;
1808                 }
1809                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1810                     return false;
1811                 }
1812                 parent = parent.parentNode;
1813             }
1814             return false;
1815         }
1816     },
1817
1818     getRegion : function(el) {
1819         return Roo.lib.Region.getRegion(el);
1820     },
1821
1822     getY : function(el) {
1823         return this.getXY(el)[1];
1824     },
1825
1826     getX : function(el) {
1827         return this.getXY(el)[0];
1828     },
1829
1830     getXY : function(el) {
1831         var p, pe, b, scroll, bd = document.body;
1832         el = Roo.getDom(el);
1833         var fly = Roo.lib.AnimBase.fly;
1834         if (el.getBoundingClientRect) {
1835             b = el.getBoundingClientRect();
1836             scroll = fly(document).getScroll();
1837             return [b.left + scroll.left, b.top + scroll.top];
1838         }
1839         var x = 0, y = 0;
1840
1841         p = el;
1842
1843         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1844
1845         while (p) {
1846
1847             x += p.offsetLeft;
1848             y += p.offsetTop;
1849
1850             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1851                 hasAbsolute = true;
1852             }
1853
1854             if (Roo.isGecko) {
1855                 pe = fly(p);
1856
1857                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1858                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1859
1860
1861                 x += bl;
1862                 y += bt;
1863
1864
1865                 if (p != el && pe.getStyle('overflow') != 'visible') {
1866                     x += bl;
1867                     y += bt;
1868                 }
1869             }
1870             p = p.offsetParent;
1871         }
1872
1873         if (Roo.isSafari && hasAbsolute) {
1874             x -= bd.offsetLeft;
1875             y -= bd.offsetTop;
1876         }
1877
1878         if (Roo.isGecko && !hasAbsolute) {
1879             var dbd = fly(bd);
1880             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1881             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1882         }
1883
1884         p = el.parentNode;
1885         while (p && p != bd) {
1886             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1887                 x -= p.scrollLeft;
1888                 y -= p.scrollTop;
1889             }
1890             p = p.parentNode;
1891         }
1892         return [x, y];
1893     },
1894  
1895   
1896
1897
1898     setXY : function(el, xy) {
1899         el = Roo.fly(el, '_setXY');
1900         el.position();
1901         var pts = el.translatePoints(xy);
1902         if (xy[0] !== false) {
1903             el.dom.style.left = pts.left + "px";
1904         }
1905         if (xy[1] !== false) {
1906             el.dom.style.top = pts.top + "px";
1907         }
1908     },
1909
1910     setX : function(el, x) {
1911         this.setXY(el, [x, false]);
1912     },
1913
1914     setY : function(el, y) {
1915         this.setXY(el, [false, y]);
1916     }
1917 };
1918 /*
1919  * Portions of this file are based on pieces of Yahoo User Interface Library
1920  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1921  * YUI licensed under the BSD License:
1922  * http://developer.yahoo.net/yui/license.txt
1923  * <script type="text/javascript">
1924  *
1925  */
1926
1927 Roo.lib.Event = function() {
1928     var loadComplete = false;
1929     var listeners = [];
1930     var unloadListeners = [];
1931     var retryCount = 0;
1932     var onAvailStack = [];
1933     var counter = 0;
1934     var lastError = null;
1935
1936     return {
1937         POLL_RETRYS: 200,
1938         POLL_INTERVAL: 20,
1939         EL: 0,
1940         TYPE: 1,
1941         FN: 2,
1942         WFN: 3,
1943         OBJ: 3,
1944         ADJ_SCOPE: 4,
1945         _interval: null,
1946
1947         startInterval: function() {
1948             if (!this._interval) {
1949                 var self = this;
1950                 var callback = function() {
1951                     self._tryPreloadAttach();
1952                 };
1953                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1954
1955             }
1956         },
1957
1958         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1959             onAvailStack.push({ id:         p_id,
1960                 fn:         p_fn,
1961                 obj:        p_obj,
1962                 override:   p_override,
1963                 checkReady: false    });
1964
1965             retryCount = this.POLL_RETRYS;
1966             this.startInterval();
1967         },
1968
1969
1970         addListener: function(el, eventName, fn) {
1971             el = Roo.getDom(el);
1972             if (!el || !fn) {
1973                 return false;
1974             }
1975
1976             if ("unload" == eventName) {
1977                 unloadListeners[unloadListeners.length] =
1978                 [el, eventName, fn];
1979                 return true;
1980             }
1981
1982             var wrappedFn = function(e) {
1983                 return fn(Roo.lib.Event.getEvent(e));
1984             };
1985
1986             var li = [el, eventName, fn, wrappedFn];
1987
1988             var index = listeners.length;
1989             listeners[index] = li;
1990
1991             this.doAdd(el, eventName, wrappedFn, false);
1992             return true;
1993
1994         },
1995
1996
1997         removeListener: function(el, eventName, fn) {
1998             var i, len;
1999
2000             el = Roo.getDom(el);
2001
2002             if(!fn) {
2003                 return this.purgeElement(el, false, eventName);
2004             }
2005
2006
2007             if ("unload" == eventName) {
2008
2009                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2010                     var li = unloadListeners[i];
2011                     if (li &&
2012                         li[0] == el &&
2013                         li[1] == eventName &&
2014                         li[2] == fn) {
2015                         unloadListeners.splice(i, 1);
2016                         return true;
2017                     }
2018                 }
2019
2020                 return false;
2021             }
2022
2023             var cacheItem = null;
2024
2025
2026             var index = arguments[3];
2027
2028             if ("undefined" == typeof index) {
2029                 index = this._getCacheIndex(el, eventName, fn);
2030             }
2031
2032             if (index >= 0) {
2033                 cacheItem = listeners[index];
2034             }
2035
2036             if (!el || !cacheItem) {
2037                 return false;
2038             }
2039
2040             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2041
2042             delete listeners[index][this.WFN];
2043             delete listeners[index][this.FN];
2044             listeners.splice(index, 1);
2045
2046             return true;
2047
2048         },
2049
2050
2051         getTarget: function(ev, resolveTextNode) {
2052             ev = ev.browserEvent || ev;
2053             var t = ev.target || ev.srcElement;
2054             return this.resolveTextNode(t);
2055         },
2056
2057
2058         resolveTextNode: function(node) {
2059             if (Roo.isSafari && node && 3 == node.nodeType) {
2060                 return node.parentNode;
2061             } else {
2062                 return node;
2063             }
2064         },
2065
2066
2067         getPageX: function(ev) {
2068             ev = ev.browserEvent || ev;
2069             var x = ev.pageX;
2070             if (!x && 0 !== x) {
2071                 x = ev.clientX || 0;
2072
2073                 if (Roo.isIE) {
2074                     x += this.getScroll()[1];
2075                 }
2076             }
2077
2078             return x;
2079         },
2080
2081
2082         getPageY: function(ev) {
2083             ev = ev.browserEvent || ev;
2084             var y = ev.pageY;
2085             if (!y && 0 !== y) {
2086                 y = ev.clientY || 0;
2087
2088                 if (Roo.isIE) {
2089                     y += this.getScroll()[0];
2090                 }
2091             }
2092
2093
2094             return y;
2095         },
2096
2097
2098         getXY: function(ev) {
2099             ev = ev.browserEvent || ev;
2100             return [this.getPageX(ev), this.getPageY(ev)];
2101         },
2102
2103
2104         getRelatedTarget: function(ev) {
2105             ev = ev.browserEvent || ev;
2106             var t = ev.relatedTarget;
2107             if (!t) {
2108                 if (ev.type == "mouseout") {
2109                     t = ev.toElement;
2110                 } else if (ev.type == "mouseover") {
2111                     t = ev.fromElement;
2112                 }
2113             }
2114
2115             return this.resolveTextNode(t);
2116         },
2117
2118
2119         getTime: function(ev) {
2120             ev = ev.browserEvent || ev;
2121             if (!ev.time) {
2122                 var t = new Date().getTime();
2123                 try {
2124                     ev.time = t;
2125                 } catch(ex) {
2126                     this.lastError = ex;
2127                     return t;
2128                 }
2129             }
2130
2131             return ev.time;
2132         },
2133
2134
2135         stopEvent: function(ev) {
2136             this.stopPropagation(ev);
2137             this.preventDefault(ev);
2138         },
2139
2140
2141         stopPropagation: function(ev) {
2142             ev = ev.browserEvent || ev;
2143             if (ev.stopPropagation) {
2144                 ev.stopPropagation();
2145             } else {
2146                 ev.cancelBubble = true;
2147             }
2148         },
2149
2150
2151         preventDefault: function(ev) {
2152             ev = ev.browserEvent || ev;
2153             if(ev.preventDefault) {
2154                 ev.preventDefault();
2155             } else {
2156                 ev.returnValue = false;
2157             }
2158         },
2159
2160
2161         getEvent: function(e) {
2162             var ev = e || window.event;
2163             if (!ev) {
2164                 var c = this.getEvent.caller;
2165                 while (c) {
2166                     ev = c.arguments[0];
2167                     if (ev && Event == ev.constructor) {
2168                         break;
2169                     }
2170                     c = c.caller;
2171                 }
2172             }
2173             return ev;
2174         },
2175
2176
2177         getCharCode: function(ev) {
2178             ev = ev.browserEvent || ev;
2179             return ev.charCode || ev.keyCode || 0;
2180         },
2181
2182
2183         _getCacheIndex: function(el, eventName, fn) {
2184             for (var i = 0,len = listeners.length; i < len; ++i) {
2185                 var li = listeners[i];
2186                 if (li &&
2187                     li[this.FN] == fn &&
2188                     li[this.EL] == el &&
2189                     li[this.TYPE] == eventName) {
2190                     return i;
2191                 }
2192             }
2193
2194             return -1;
2195         },
2196
2197
2198         elCache: {},
2199
2200
2201         getEl: function(id) {
2202             return document.getElementById(id);
2203         },
2204
2205
2206         clearCache: function() {
2207         },
2208
2209
2210         _load: function(e) {
2211             loadComplete = true;
2212             var EU = Roo.lib.Event;
2213
2214
2215             if (Roo.isIE) {
2216                 EU.doRemove(window, "load", EU._load);
2217             }
2218         },
2219
2220
2221         _tryPreloadAttach: function() {
2222
2223             if (this.locked) {
2224                 return false;
2225             }
2226
2227             this.locked = true;
2228
2229
2230             var tryAgain = !loadComplete;
2231             if (!tryAgain) {
2232                 tryAgain = (retryCount > 0);
2233             }
2234
2235
2236             var notAvail = [];
2237             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2238                 var item = onAvailStack[i];
2239                 if (item) {
2240                     var el = this.getEl(item.id);
2241
2242                     if (el) {
2243                         if (!item.checkReady ||
2244                             loadComplete ||
2245                             el.nextSibling ||
2246                             (document && document.body)) {
2247
2248                             var scope = el;
2249                             if (item.override) {
2250                                 if (item.override === true) {
2251                                     scope = item.obj;
2252                                 } else {
2253                                     scope = item.override;
2254                                 }
2255                             }
2256                             item.fn.call(scope, item.obj);
2257                             onAvailStack[i] = null;
2258                         }
2259                     } else {
2260                         notAvail.push(item);
2261                     }
2262                 }
2263             }
2264
2265             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2266
2267             if (tryAgain) {
2268
2269                 this.startInterval();
2270             } else {
2271                 clearInterval(this._interval);
2272                 this._interval = null;
2273             }
2274
2275             this.locked = false;
2276
2277             return true;
2278
2279         },
2280
2281
2282         purgeElement: function(el, recurse, eventName) {
2283             var elListeners = this.getListeners(el, eventName);
2284             if (elListeners) {
2285                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2286                     var l = elListeners[i];
2287                     this.removeListener(el, l.type, l.fn);
2288                 }
2289             }
2290
2291             if (recurse && el && el.childNodes) {
2292                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2293                     this.purgeElement(el.childNodes[i], recurse, eventName);
2294                 }
2295             }
2296         },
2297
2298
2299         getListeners: function(el, eventName) {
2300             var results = [], searchLists;
2301             if (!eventName) {
2302                 searchLists = [listeners, unloadListeners];
2303             } else if (eventName == "unload") {
2304                 searchLists = [unloadListeners];
2305             } else {
2306                 searchLists = [listeners];
2307             }
2308
2309             for (var j = 0; j < searchLists.length; ++j) {
2310                 var searchList = searchLists[j];
2311                 if (searchList && searchList.length > 0) {
2312                     for (var i = 0,len = searchList.length; i < len; ++i) {
2313                         var l = searchList[i];
2314                         if (l && l[this.EL] === el &&
2315                             (!eventName || eventName === l[this.TYPE])) {
2316                             results.push({
2317                                 type:   l[this.TYPE],
2318                                 fn:     l[this.FN],
2319                                 obj:    l[this.OBJ],
2320                                 adjust: l[this.ADJ_SCOPE],
2321                                 index:  i
2322                             });
2323                         }
2324                     }
2325                 }
2326             }
2327
2328             return (results.length) ? results : null;
2329         },
2330
2331
2332         _unload: function(e) {
2333
2334             var EU = Roo.lib.Event, i, j, l, len, index;
2335
2336             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2337                 l = unloadListeners[i];
2338                 if (l) {
2339                     var scope = window;
2340                     if (l[EU.ADJ_SCOPE]) {
2341                         if (l[EU.ADJ_SCOPE] === true) {
2342                             scope = l[EU.OBJ];
2343                         } else {
2344                             scope = l[EU.ADJ_SCOPE];
2345                         }
2346                     }
2347                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2348                     unloadListeners[i] = null;
2349                     l = null;
2350                     scope = null;
2351                 }
2352             }
2353
2354             unloadListeners = null;
2355
2356             if (listeners && listeners.length > 0) {
2357                 j = listeners.length;
2358                 while (j) {
2359                     index = j - 1;
2360                     l = listeners[index];
2361                     if (l) {
2362                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2363                                 l[EU.FN], index);
2364                     }
2365                     j = j - 1;
2366                 }
2367                 l = null;
2368
2369                 EU.clearCache();
2370             }
2371
2372             EU.doRemove(window, "unload", EU._unload);
2373
2374         },
2375
2376
2377         getScroll: function() {
2378             var dd = document.documentElement, db = document.body;
2379             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2380                 return [dd.scrollTop, dd.scrollLeft];
2381             } else if (db) {
2382                 return [db.scrollTop, db.scrollLeft];
2383             } else {
2384                 return [0, 0];
2385             }
2386         },
2387
2388
2389         doAdd: function () {
2390             if (window.addEventListener) {
2391                 return function(el, eventName, fn, capture) {
2392                     el.addEventListener(eventName, fn, (capture));
2393                 };
2394             } else if (window.attachEvent) {
2395                 return function(el, eventName, fn, capture) {
2396                     el.attachEvent("on" + eventName, fn);
2397                 };
2398             } else {
2399                 return function() {
2400                 };
2401             }
2402         }(),
2403
2404
2405         doRemove: function() {
2406             if (window.removeEventListener) {
2407                 return function (el, eventName, fn, capture) {
2408                     el.removeEventListener(eventName, fn, (capture));
2409                 };
2410             } else if (window.detachEvent) {
2411                 return function (el, eventName, fn) {
2412                     el.detachEvent("on" + eventName, fn);
2413                 };
2414             } else {
2415                 return function() {
2416                 };
2417             }
2418         }()
2419     };
2420     
2421 }();
2422 (function() {     
2423    
2424     var E = Roo.lib.Event;
2425     E.on = E.addListener;
2426     E.un = E.removeListener;
2427
2428     if (document && document.body) {
2429         E._load();
2430     } else {
2431         E.doAdd(window, "load", E._load);
2432     }
2433     E.doAdd(window, "unload", E._unload);
2434     E._tryPreloadAttach();
2435 })();
2436
2437 /*
2438  * Portions of this file are based on pieces of Yahoo User Interface Library
2439  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2440  * YUI licensed under the BSD License:
2441  * http://developer.yahoo.net/yui/license.txt
2442  * <script type="text/javascript">
2443  *
2444  */
2445
2446 (function() {
2447     
2448     Roo.lib.Ajax = {
2449         request : function(method, uri, cb, data, options) {
2450             if(options){
2451                 var hs = options.headers;
2452                 if(hs){
2453                     for(var h in hs){
2454                         if(hs.hasOwnProperty(h)){
2455                             this.initHeader(h, hs[h], false);
2456                         }
2457                     }
2458                 }
2459                 if(options.xmlData){
2460                     this.initHeader('Content-Type', 'text/xml', false);
2461                     method = 'POST';
2462                     data = options.xmlData;
2463                 }
2464             }
2465
2466             return this.asyncRequest(method, uri, cb, data);
2467         },
2468
2469         serializeForm : function(form) {
2470             if(typeof form == 'string') {
2471                 form = (document.getElementById(form) || document.forms[form]);
2472             }
2473
2474             var el, name, val, disabled, data = '', hasSubmit = false;
2475             for (var i = 0; i < form.elements.length; i++) {
2476                 el = form.elements[i];
2477                 disabled = form.elements[i].disabled;
2478                 name = form.elements[i].name;
2479                 val = form.elements[i].value;
2480
2481                 if (!disabled && name){
2482                     switch (el.type)
2483                             {
2484                         case 'select-one':
2485                         case 'select-multiple':
2486                             for (var j = 0; j < el.options.length; j++) {
2487                                 if (el.options[j].selected) {
2488                                     if (Roo.isIE) {
2489                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2490                                     }
2491                                     else {
2492                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2493                                     }
2494                                 }
2495                             }
2496                             break;
2497                         case 'radio':
2498                         case 'checkbox':
2499                             if (el.checked) {
2500                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2501                             }
2502                             break;
2503                         case 'file':
2504
2505                         case undefined:
2506
2507                         case 'reset':
2508
2509                         case 'button':
2510
2511                             break;
2512                         case 'submit':
2513                             if(hasSubmit == false) {
2514                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2515                                 hasSubmit = true;
2516                             }
2517                             break;
2518                         default:
2519                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2520                             break;
2521                     }
2522                 }
2523             }
2524             data = data.substr(0, data.length - 1);
2525             return data;
2526         },
2527
2528         headers:{},
2529
2530         hasHeaders:false,
2531
2532         useDefaultHeader:true,
2533
2534         defaultPostHeader:'application/x-www-form-urlencoded',
2535
2536         useDefaultXhrHeader:true,
2537
2538         defaultXhrHeader:'XMLHttpRequest',
2539
2540         hasDefaultHeaders:true,
2541
2542         defaultHeaders:{},
2543
2544         poll:{},
2545
2546         timeout:{},
2547
2548         pollInterval:50,
2549
2550         transactionId:0,
2551
2552         setProgId:function(id)
2553         {
2554             this.activeX.unshift(id);
2555         },
2556
2557         setDefaultPostHeader:function(b)
2558         {
2559             this.useDefaultHeader = b;
2560         },
2561
2562         setDefaultXhrHeader:function(b)
2563         {
2564             this.useDefaultXhrHeader = b;
2565         },
2566
2567         setPollingInterval:function(i)
2568         {
2569             if (typeof i == 'number' && isFinite(i)) {
2570                 this.pollInterval = i;
2571             }
2572         },
2573
2574         createXhrObject:function(transactionId)
2575         {
2576             var obj,http;
2577             try
2578             {
2579
2580                 http = new XMLHttpRequest();
2581
2582                 obj = { conn:http, tId:transactionId };
2583             }
2584             catch(e)
2585             {
2586                 for (var i = 0; i < this.activeX.length; ++i) {
2587                     try
2588                     {
2589
2590                         http = new ActiveXObject(this.activeX[i]);
2591
2592                         obj = { conn:http, tId:transactionId };
2593                         break;
2594                     }
2595                     catch(e) {
2596                     }
2597                 }
2598             }
2599             finally
2600             {
2601                 return obj;
2602             }
2603         },
2604
2605         getConnectionObject:function()
2606         {
2607             var o;
2608             var tId = this.transactionId;
2609
2610             try
2611             {
2612                 o = this.createXhrObject(tId);
2613                 if (o) {
2614                     this.transactionId++;
2615                 }
2616             }
2617             catch(e) {
2618             }
2619             finally
2620             {
2621                 return o;
2622             }
2623         },
2624
2625         asyncRequest:function(method, uri, callback, postData)
2626         {
2627             var o = this.getConnectionObject();
2628
2629             if (!o) {
2630                 return null;
2631             }
2632             else {
2633                 o.conn.open(method, uri, true);
2634
2635                 if (this.useDefaultXhrHeader) {
2636                     if (!this.defaultHeaders['X-Requested-With']) {
2637                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2638                     }
2639                 }
2640
2641                 if(postData && this.useDefaultHeader){
2642                     this.initHeader('Content-Type', this.defaultPostHeader);
2643                 }
2644
2645                  if (this.hasDefaultHeaders || this.hasHeaders) {
2646                     this.setHeader(o);
2647                 }
2648
2649                 this.handleReadyState(o, callback);
2650                 o.conn.send(postData || null);
2651
2652                 return o;
2653             }
2654         },
2655
2656         handleReadyState:function(o, callback)
2657         {
2658             var oConn = this;
2659
2660             if (callback && callback.timeout) {
2661                 this.timeout[o.tId] = window.setTimeout(function() {
2662                     oConn.abort(o, callback, true);
2663                 }, callback.timeout);
2664             }
2665
2666             this.poll[o.tId] = window.setInterval(
2667                     function() {
2668                         if (o.conn && o.conn.readyState == 4) {
2669                             window.clearInterval(oConn.poll[o.tId]);
2670                             delete oConn.poll[o.tId];
2671
2672                             if(callback && callback.timeout) {
2673                                 window.clearTimeout(oConn.timeout[o.tId]);
2674                                 delete oConn.timeout[o.tId];
2675                             }
2676
2677                             oConn.handleTransactionResponse(o, callback);
2678                         }
2679                     }
2680                     , this.pollInterval);
2681         },
2682
2683         handleTransactionResponse:function(o, callback, isAbort)
2684         {
2685
2686             if (!callback) {
2687                 this.releaseObject(o);
2688                 return;
2689             }
2690
2691             var httpStatus, responseObject;
2692
2693             try
2694             {
2695                 if (o.conn.status !== undefined && o.conn.status != 0) {
2696                     httpStatus = o.conn.status;
2697                 }
2698                 else {
2699                     httpStatus = 13030;
2700                 }
2701             }
2702             catch(e) {
2703
2704
2705                 httpStatus = 13030;
2706             }
2707
2708             if (httpStatus >= 200 && httpStatus < 300) {
2709                 responseObject = this.createResponseObject(o, callback.argument);
2710                 if (callback.success) {
2711                     if (!callback.scope) {
2712                         callback.success(responseObject);
2713                     }
2714                     else {
2715
2716
2717                         callback.success.apply(callback.scope, [responseObject]);
2718                     }
2719                 }
2720             }
2721             else {
2722                 switch (httpStatus) {
2723
2724                     case 12002:
2725                     case 12029:
2726                     case 12030:
2727                     case 12031:
2728                     case 12152:
2729                     case 13030:
2730                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2731                         if (callback.failure) {
2732                             if (!callback.scope) {
2733                                 callback.failure(responseObject);
2734                             }
2735                             else {
2736                                 callback.failure.apply(callback.scope, [responseObject]);
2737                             }
2738                         }
2739                         break;
2740                     default:
2741                         responseObject = this.createResponseObject(o, callback.argument);
2742                         if (callback.failure) {
2743                             if (!callback.scope) {
2744                                 callback.failure(responseObject);
2745                             }
2746                             else {
2747                                 callback.failure.apply(callback.scope, [responseObject]);
2748                             }
2749                         }
2750                 }
2751             }
2752
2753             this.releaseObject(o);
2754             responseObject = null;
2755         },
2756
2757         createResponseObject:function(o, callbackArg)
2758         {
2759             var obj = {};
2760             var headerObj = {};
2761
2762             try
2763             {
2764                 var headerStr = o.conn.getAllResponseHeaders();
2765                 var header = headerStr.split('\n');
2766                 for (var i = 0; i < header.length; i++) {
2767                     var delimitPos = header[i].indexOf(':');
2768                     if (delimitPos != -1) {
2769                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2770                     }
2771                 }
2772             }
2773             catch(e) {
2774             }
2775
2776             obj.tId = o.tId;
2777             obj.status = o.conn.status;
2778             obj.statusText = o.conn.statusText;
2779             obj.getResponseHeader = headerObj;
2780             obj.getAllResponseHeaders = headerStr;
2781             obj.responseText = o.conn.responseText;
2782             obj.responseXML = o.conn.responseXML;
2783
2784             if (typeof callbackArg !== undefined) {
2785                 obj.argument = callbackArg;
2786             }
2787
2788             return obj;
2789         },
2790
2791         createExceptionObject:function(tId, callbackArg, isAbort)
2792         {
2793             var COMM_CODE = 0;
2794             var COMM_ERROR = 'communication failure';
2795             var ABORT_CODE = -1;
2796             var ABORT_ERROR = 'transaction aborted';
2797
2798             var obj = {};
2799
2800             obj.tId = tId;
2801             if (isAbort) {
2802                 obj.status = ABORT_CODE;
2803                 obj.statusText = ABORT_ERROR;
2804             }
2805             else {
2806                 obj.status = COMM_CODE;
2807                 obj.statusText = COMM_ERROR;
2808             }
2809
2810             if (callbackArg) {
2811                 obj.argument = callbackArg;
2812             }
2813
2814             return obj;
2815         },
2816
2817         initHeader:function(label, value, isDefault)
2818         {
2819             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2820
2821             if (headerObj[label] === undefined) {
2822                 headerObj[label] = value;
2823             }
2824             else {
2825
2826
2827                 headerObj[label] = value + "," + headerObj[label];
2828             }
2829
2830             if (isDefault) {
2831                 this.hasDefaultHeaders = true;
2832             }
2833             else {
2834                 this.hasHeaders = true;
2835             }
2836         },
2837
2838
2839         setHeader:function(o)
2840         {
2841             if (this.hasDefaultHeaders) {
2842                 for (var prop in this.defaultHeaders) {
2843                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2844                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2845                     }
2846                 }
2847             }
2848
2849             if (this.hasHeaders) {
2850                 for (var prop in this.headers) {
2851                     if (this.headers.hasOwnProperty(prop)) {
2852                         o.conn.setRequestHeader(prop, this.headers[prop]);
2853                     }
2854                 }
2855                 this.headers = {};
2856                 this.hasHeaders = false;
2857             }
2858         },
2859
2860         resetDefaultHeaders:function() {
2861             delete this.defaultHeaders;
2862             this.defaultHeaders = {};
2863             this.hasDefaultHeaders = false;
2864         },
2865
2866         abort:function(o, callback, isTimeout)
2867         {
2868             if(this.isCallInProgress(o)) {
2869                 o.conn.abort();
2870                 window.clearInterval(this.poll[o.tId]);
2871                 delete this.poll[o.tId];
2872                 if (isTimeout) {
2873                     delete this.timeout[o.tId];
2874                 }
2875
2876                 this.handleTransactionResponse(o, callback, true);
2877
2878                 return true;
2879             }
2880             else {
2881                 return false;
2882             }
2883         },
2884
2885
2886         isCallInProgress:function(o)
2887         {
2888             if (o && o.conn) {
2889                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2890             }
2891             else {
2892
2893                 return false;
2894             }
2895         },
2896
2897
2898         releaseObject:function(o)
2899         {
2900
2901             o.conn = null;
2902
2903             o = null;
2904         },
2905
2906         activeX:[
2907         'MSXML2.XMLHTTP.3.0',
2908         'MSXML2.XMLHTTP',
2909         'Microsoft.XMLHTTP'
2910         ]
2911
2912
2913     };
2914 })();/*
2915  * Portions of this file are based on pieces of Yahoo User Interface Library
2916  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2917  * YUI licensed under the BSD License:
2918  * http://developer.yahoo.net/yui/license.txt
2919  * <script type="text/javascript">
2920  *
2921  */
2922
2923 Roo.lib.Region = function(t, r, b, l) {
2924     this.top = t;
2925     this[1] = t;
2926     this.right = r;
2927     this.bottom = b;
2928     this.left = l;
2929     this[0] = l;
2930 };
2931
2932
2933 Roo.lib.Region.prototype = {
2934     contains : function(region) {
2935         return ( region.left >= this.left &&
2936                  region.right <= this.right &&
2937                  region.top >= this.top &&
2938                  region.bottom <= this.bottom    );
2939
2940     },
2941
2942     getArea : function() {
2943         return ( (this.bottom - this.top) * (this.right - this.left) );
2944     },
2945
2946     intersect : function(region) {
2947         var t = Math.max(this.top, region.top);
2948         var r = Math.min(this.right, region.right);
2949         var b = Math.min(this.bottom, region.bottom);
2950         var l = Math.max(this.left, region.left);
2951
2952         if (b >= t && r >= l) {
2953             return new Roo.lib.Region(t, r, b, l);
2954         } else {
2955             return null;
2956         }
2957     },
2958     union : function(region) {
2959         var t = Math.min(this.top, region.top);
2960         var r = Math.max(this.right, region.right);
2961         var b = Math.max(this.bottom, region.bottom);
2962         var l = Math.min(this.left, region.left);
2963
2964         return new Roo.lib.Region(t, r, b, l);
2965     },
2966
2967     adjust : function(t, l, b, r) {
2968         this.top += t;
2969         this.left += l;
2970         this.right += r;
2971         this.bottom += b;
2972         return this;
2973     }
2974 };
2975
2976 Roo.lib.Region.getRegion = function(el) {
2977     var p = Roo.lib.Dom.getXY(el);
2978
2979     var t = p[1];
2980     var r = p[0] + el.offsetWidth;
2981     var b = p[1] + el.offsetHeight;
2982     var l = p[0];
2983
2984     return new Roo.lib.Region(t, r, b, l);
2985 };
2986 /*
2987  * Portions of this file are based on pieces of Yahoo User Interface Library
2988  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2989  * YUI licensed under the BSD License:
2990  * http://developer.yahoo.net/yui/license.txt
2991  * <script type="text/javascript">
2992  *
2993  */
2994 //@@dep Roo.lib.Region
2995
2996
2997 Roo.lib.Point = function(x, y) {
2998     if (x instanceof Array) {
2999         y = x[1];
3000         x = x[0];
3001     }
3002     this.x = this.right = this.left = this[0] = x;
3003     this.y = this.top = this.bottom = this[1] = y;
3004 };
3005
3006 Roo.lib.Point.prototype = new Roo.lib.Region();
3007 /*
3008  * Portions of this file are based on pieces of Yahoo User Interface Library
3009  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010  * YUI licensed under the BSD License:
3011  * http://developer.yahoo.net/yui/license.txt
3012  * <script type="text/javascript">
3013  *
3014  */
3015  
3016 (function() {   
3017
3018     Roo.lib.Anim = {
3019         scroll : function(el, args, duration, easing, cb, scope) {
3020             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3021         },
3022
3023         motion : function(el, args, duration, easing, cb, scope) {
3024             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3025         },
3026
3027         color : function(el, args, duration, easing, cb, scope) {
3028             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3029         },
3030
3031         run : function(el, args, duration, easing, cb, scope, type) {
3032             type = type || Roo.lib.AnimBase;
3033             if (typeof easing == "string") {
3034                 easing = Roo.lib.Easing[easing];
3035             }
3036             var anim = new type(el, args, duration, easing);
3037             anim.animateX(function() {
3038                 Roo.callback(cb, scope);
3039             });
3040             return anim;
3041         }
3042     };
3043 })();/*
3044  * Portions of this file are based on pieces of Yahoo User Interface Library
3045  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3046  * YUI licensed under the BSD License:
3047  * http://developer.yahoo.net/yui/license.txt
3048  * <script type="text/javascript">
3049  *
3050  */
3051
3052 (function() {    
3053     var libFlyweight;
3054     
3055     function fly(el) {
3056         if (!libFlyweight) {
3057             libFlyweight = new Roo.Element.Flyweight();
3058         }
3059         libFlyweight.dom = el;
3060         return libFlyweight;
3061     }
3062
3063     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3064     
3065    
3066     
3067     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3068         if (el) {
3069             this.init(el, attributes, duration, method);
3070         }
3071     };
3072
3073     Roo.lib.AnimBase.fly = fly;
3074     
3075     
3076     
3077     Roo.lib.AnimBase.prototype = {
3078
3079         toString: function() {
3080             var el = this.getEl();
3081             var id = el.id || el.tagName;
3082             return ("Anim " + id);
3083         },
3084
3085         patterns: {
3086             noNegatives:        /width|height|opacity|padding/i,
3087             offsetAttribute:  /^((width|height)|(top|left))$/,
3088             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3089             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3090         },
3091
3092
3093         doMethod: function(attr, start, end) {
3094             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3095         },
3096
3097
3098         setAttribute: function(attr, val, unit) {
3099             if (this.patterns.noNegatives.test(attr)) {
3100                 val = (val > 0) ? val : 0;
3101             }
3102
3103             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3104         },
3105
3106
3107         getAttribute: function(attr) {
3108             var el = this.getEl();
3109             var val = fly(el).getStyle(attr);
3110
3111             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3112                 return parseFloat(val);
3113             }
3114
3115             var a = this.patterns.offsetAttribute.exec(attr) || [];
3116             var pos = !!( a[3] );
3117             var box = !!( a[2] );
3118
3119
3120             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3121                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3122             } else {
3123                 val = 0;
3124             }
3125
3126             return val;
3127         },
3128
3129
3130         getDefaultUnit: function(attr) {
3131             if (this.patterns.defaultUnit.test(attr)) {
3132                 return 'px';
3133             }
3134
3135             return '';
3136         },
3137
3138         animateX : function(callback, scope) {
3139             var f = function() {
3140                 this.onComplete.removeListener(f);
3141                 if (typeof callback == "function") {
3142                     callback.call(scope || this, this);
3143                 }
3144             };
3145             this.onComplete.addListener(f, this);
3146             this.animate();
3147         },
3148
3149
3150         setRuntimeAttribute: function(attr) {
3151             var start;
3152             var end;
3153             var attributes = this.attributes;
3154
3155             this.runtimeAttributes[attr] = {};
3156
3157             var isset = function(prop) {
3158                 return (typeof prop !== 'undefined');
3159             };
3160
3161             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3162                 return false;
3163             }
3164
3165             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3166
3167
3168             if (isset(attributes[attr]['to'])) {
3169                 end = attributes[attr]['to'];
3170             } else if (isset(attributes[attr]['by'])) {
3171                 if (start.constructor == Array) {
3172                     end = [];
3173                     for (var i = 0, len = start.length; i < len; ++i) {
3174                         end[i] = start[i] + attributes[attr]['by'][i];
3175                     }
3176                 } else {
3177                     end = start + attributes[attr]['by'];
3178                 }
3179             }
3180
3181             this.runtimeAttributes[attr].start = start;
3182             this.runtimeAttributes[attr].end = end;
3183
3184
3185             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3186         },
3187
3188
3189         init: function(el, attributes, duration, method) {
3190
3191             var isAnimated = false;
3192
3193
3194             var startTime = null;
3195
3196
3197             var actualFrames = 0;
3198
3199
3200             el = Roo.getDom(el);
3201
3202
3203             this.attributes = attributes || {};
3204
3205
3206             this.duration = duration || 1;
3207
3208
3209             this.method = method || Roo.lib.Easing.easeNone;
3210
3211
3212             this.useSeconds = true;
3213
3214
3215             this.currentFrame = 0;
3216
3217
3218             this.totalFrames = Roo.lib.AnimMgr.fps;
3219
3220
3221             this.getEl = function() {
3222                 return el;
3223             };
3224
3225
3226             this.isAnimated = function() {
3227                 return isAnimated;
3228             };
3229
3230
3231             this.getStartTime = function() {
3232                 return startTime;
3233             };
3234
3235             this.runtimeAttributes = {};
3236
3237
3238             this.animate = function() {
3239                 if (this.isAnimated()) {
3240                     return false;
3241                 }
3242
3243                 this.currentFrame = 0;
3244
3245                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3246
3247                 Roo.lib.AnimMgr.registerElement(this);
3248             };
3249
3250
3251             this.stop = function(finish) {
3252                 if (finish) {
3253                     this.currentFrame = this.totalFrames;
3254                     this._onTween.fire();
3255                 }
3256                 Roo.lib.AnimMgr.stop(this);
3257             };
3258
3259             var onStart = function() {
3260                 this.onStart.fire();
3261
3262                 this.runtimeAttributes = {};
3263                 for (var attr in this.attributes) {
3264                     this.setRuntimeAttribute(attr);
3265                 }
3266
3267                 isAnimated = true;
3268                 actualFrames = 0;
3269                 startTime = new Date();
3270             };
3271
3272
3273             var onTween = function() {
3274                 var data = {
3275                     duration: new Date() - this.getStartTime(),
3276                     currentFrame: this.currentFrame
3277                 };
3278
3279                 data.toString = function() {
3280                     return (
3281                             'duration: ' + data.duration +
3282                             ', currentFrame: ' + data.currentFrame
3283                             );
3284                 };
3285
3286                 this.onTween.fire(data);
3287
3288                 var runtimeAttributes = this.runtimeAttributes;
3289
3290                 for (var attr in runtimeAttributes) {
3291                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3292                 }
3293
3294                 actualFrames += 1;
3295             };
3296
3297             var onComplete = function() {
3298                 var actual_duration = (new Date() - startTime) / 1000 ;
3299
3300                 var data = {
3301                     duration: actual_duration,
3302                     frames: actualFrames,
3303                     fps: actualFrames / actual_duration
3304                 };
3305
3306                 data.toString = function() {
3307                     return (
3308                             'duration: ' + data.duration +
3309                             ', frames: ' + data.frames +
3310                             ', fps: ' + data.fps
3311                             );
3312                 };
3313
3314                 isAnimated = false;
3315                 actualFrames = 0;
3316                 this.onComplete.fire(data);
3317             };
3318
3319
3320             this._onStart = new Roo.util.Event(this);
3321             this.onStart = new Roo.util.Event(this);
3322             this.onTween = new Roo.util.Event(this);
3323             this._onTween = new Roo.util.Event(this);
3324             this.onComplete = new Roo.util.Event(this);
3325             this._onComplete = new Roo.util.Event(this);
3326             this._onStart.addListener(onStart);
3327             this._onTween.addListener(onTween);
3328             this._onComplete.addListener(onComplete);
3329         }
3330     };
3331 })();
3332 /*
3333  * Portions of this file are based on pieces of Yahoo User Interface Library
3334  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3335  * YUI licensed under the BSD License:
3336  * http://developer.yahoo.net/yui/license.txt
3337  * <script type="text/javascript">
3338  *
3339  */
3340
3341 Roo.lib.AnimMgr = new function() {
3342
3343         var thread = null;
3344
3345
3346         var queue = [];
3347
3348
3349         var tweenCount = 0;
3350
3351
3352         this.fps = 1000;
3353
3354
3355         this.delay = 1;
3356
3357
3358         this.registerElement = function(tween) {
3359             queue[queue.length] = tween;
3360             tweenCount += 1;
3361             tween._onStart.fire();
3362             this.start();
3363         };
3364
3365
3366         this.unRegister = function(tween, index) {
3367             tween._onComplete.fire();
3368             index = index || getIndex(tween);
3369             if (index != -1) {
3370                 queue.splice(index, 1);
3371             }
3372
3373             tweenCount -= 1;
3374             if (tweenCount <= 0) {
3375                 this.stop();
3376             }
3377         };
3378
3379
3380         this.start = function() {
3381             if (thread === null) {
3382                 thread = setInterval(this.run, this.delay);
3383             }
3384         };
3385
3386
3387         this.stop = function(tween) {
3388             if (!tween) {
3389                 clearInterval(thread);
3390
3391                 for (var i = 0, len = queue.length; i < len; ++i) {
3392                     if (queue[0].isAnimated()) {
3393                         this.unRegister(queue[0], 0);
3394                     }
3395                 }
3396
3397                 queue = [];
3398                 thread = null;
3399                 tweenCount = 0;
3400             }
3401             else {
3402                 this.unRegister(tween);
3403             }
3404         };
3405
3406
3407         this.run = function() {
3408             for (var i = 0, len = queue.length; i < len; ++i) {
3409                 var tween = queue[i];
3410                 if (!tween || !tween.isAnimated()) {
3411                     continue;
3412                 }
3413
3414                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3415                 {
3416                     tween.currentFrame += 1;
3417
3418                     if (tween.useSeconds) {
3419                         correctFrame(tween);
3420                     }
3421                     tween._onTween.fire();
3422                 }
3423                 else {
3424                     Roo.lib.AnimMgr.stop(tween, i);
3425                 }
3426             }
3427         };
3428
3429         var getIndex = function(anim) {
3430             for (var i = 0, len = queue.length; i < len; ++i) {
3431                 if (queue[i] == anim) {
3432                     return i;
3433                 }
3434             }
3435             return -1;
3436         };
3437
3438
3439         var correctFrame = function(tween) {
3440             var frames = tween.totalFrames;
3441             var frame = tween.currentFrame;
3442             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3443             var elapsed = (new Date() - tween.getStartTime());
3444             var tweak = 0;
3445
3446             if (elapsed < tween.duration * 1000) {
3447                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3448             } else {
3449                 tweak = frames - (frame + 1);
3450             }
3451             if (tweak > 0 && isFinite(tweak)) {
3452                 if (tween.currentFrame + tweak >= frames) {
3453                     tweak = frames - (frame + 1);
3454                 }
3455
3456                 tween.currentFrame += tweak;
3457             }
3458         };
3459     };/*
3460  * Portions of this file are based on pieces of Yahoo User Interface Library
3461  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3462  * YUI licensed under the BSD License:
3463  * http://developer.yahoo.net/yui/license.txt
3464  * <script type="text/javascript">
3465  *
3466  */
3467 Roo.lib.Bezier = new function() {
3468
3469         this.getPosition = function(points, t) {
3470             var n = points.length;
3471             var tmp = [];
3472
3473             for (var i = 0; i < n; ++i) {
3474                 tmp[i] = [points[i][0], points[i][1]];
3475             }
3476
3477             for (var j = 1; j < n; ++j) {
3478                 for (i = 0; i < n - j; ++i) {
3479                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3480                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3481                 }
3482             }
3483
3484             return [ tmp[0][0], tmp[0][1] ];
3485
3486         };
3487     };/*
3488  * Portions of this file are based on pieces of Yahoo User Interface Library
3489  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3490  * YUI licensed under the BSD License:
3491  * http://developer.yahoo.net/yui/license.txt
3492  * <script type="text/javascript">
3493  *
3494  */
3495 (function() {
3496
3497     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3498         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3499     };
3500
3501     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3502
3503     var fly = Roo.lib.AnimBase.fly;
3504     var Y = Roo.lib;
3505     var superclass = Y.ColorAnim.superclass;
3506     var proto = Y.ColorAnim.prototype;
3507
3508     proto.toString = function() {
3509         var el = this.getEl();
3510         var id = el.id || el.tagName;
3511         return ("ColorAnim " + id);
3512     };
3513
3514     proto.patterns.color = /color$/i;
3515     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3516     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3517     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3518     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3519
3520
3521     proto.parseColor = function(s) {
3522         if (s.length == 3) {
3523             return s;
3524         }
3525
3526         var c = this.patterns.hex.exec(s);
3527         if (c && c.length == 4) {
3528             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3529         }
3530
3531         c = this.patterns.rgb.exec(s);
3532         if (c && c.length == 4) {
3533             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3534         }
3535
3536         c = this.patterns.hex3.exec(s);
3537         if (c && c.length == 4) {
3538             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3539         }
3540
3541         return null;
3542     };
3543     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3544     proto.getAttribute = function(attr) {
3545         var el = this.getEl();
3546         if (this.patterns.color.test(attr)) {
3547             var val = fly(el).getStyle(attr);
3548
3549             if (this.patterns.transparent.test(val)) {
3550                 var parent = el.parentNode;
3551                 val = fly(parent).getStyle(attr);
3552
3553                 while (parent && this.patterns.transparent.test(val)) {
3554                     parent = parent.parentNode;
3555                     val = fly(parent).getStyle(attr);
3556                     if (parent.tagName.toUpperCase() == 'HTML') {
3557                         val = '#fff';
3558                     }
3559                 }
3560             }
3561         } else {
3562             val = superclass.getAttribute.call(this, attr);
3563         }
3564
3565         return val;
3566     };
3567     proto.getAttribute = function(attr) {
3568         var el = this.getEl();
3569         if (this.patterns.color.test(attr)) {
3570             var val = fly(el).getStyle(attr);
3571
3572             if (this.patterns.transparent.test(val)) {
3573                 var parent = el.parentNode;
3574                 val = fly(parent).getStyle(attr);
3575
3576                 while (parent && this.patterns.transparent.test(val)) {
3577                     parent = parent.parentNode;
3578                     val = fly(parent).getStyle(attr);
3579                     if (parent.tagName.toUpperCase() == 'HTML') {
3580                         val = '#fff';
3581                     }
3582                 }
3583             }
3584         } else {
3585             val = superclass.getAttribute.call(this, attr);
3586         }
3587
3588         return val;
3589     };
3590
3591     proto.doMethod = function(attr, start, end) {
3592         var val;
3593
3594         if (this.patterns.color.test(attr)) {
3595             val = [];
3596             for (var i = 0, len = start.length; i < len; ++i) {
3597                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3598             }
3599
3600             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3601         }
3602         else {
3603             val = superclass.doMethod.call(this, attr, start, end);
3604         }
3605
3606         return val;
3607     };
3608
3609     proto.setRuntimeAttribute = function(attr) {
3610         superclass.setRuntimeAttribute.call(this, attr);
3611
3612         if (this.patterns.color.test(attr)) {
3613             var attributes = this.attributes;
3614             var start = this.parseColor(this.runtimeAttributes[attr].start);
3615             var end = this.parseColor(this.runtimeAttributes[attr].end);
3616
3617             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3618                 end = this.parseColor(attributes[attr].by);
3619
3620                 for (var i = 0, len = start.length; i < len; ++i) {
3621                     end[i] = start[i] + end[i];
3622                 }
3623             }
3624
3625             this.runtimeAttributes[attr].start = start;
3626             this.runtimeAttributes[attr].end = end;
3627         }
3628     };
3629 })();
3630
3631 /*
3632  * Portions of this file are based on pieces of Yahoo User Interface Library
3633  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3634  * YUI licensed under the BSD License:
3635  * http://developer.yahoo.net/yui/license.txt
3636  * <script type="text/javascript">
3637  *
3638  */
3639 Roo.lib.Easing = {
3640
3641
3642     easeNone: function (t, b, c, d) {
3643         return c * t / d + b;
3644     },
3645
3646
3647     easeIn: function (t, b, c, d) {
3648         return c * (t /= d) * t + b;
3649     },
3650
3651
3652     easeOut: function (t, b, c, d) {
3653         return -c * (t /= d) * (t - 2) + b;
3654     },
3655
3656
3657     easeBoth: function (t, b, c, d) {
3658         if ((t /= d / 2) < 1) {
3659             return c / 2 * t * t + b;
3660         }
3661
3662         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3663     },
3664
3665
3666     easeInStrong: function (t, b, c, d) {
3667         return c * (t /= d) * t * t * t + b;
3668     },
3669
3670
3671     easeOutStrong: function (t, b, c, d) {
3672         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3673     },
3674
3675
3676     easeBothStrong: function (t, b, c, d) {
3677         if ((t /= d / 2) < 1) {
3678             return c / 2 * t * t * t * t + b;
3679         }
3680
3681         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3682     },
3683
3684
3685
3686     elasticIn: function (t, b, c, d, a, p) {
3687         if (t == 0) {
3688             return b;
3689         }
3690         if ((t /= d) == 1) {
3691             return b + c;
3692         }
3693         if (!p) {
3694             p = d * .3;
3695         }
3696
3697         if (!a || a < Math.abs(c)) {
3698             a = c;
3699             var s = p / 4;
3700         }
3701         else {
3702             var s = p / (2 * Math.PI) * Math.asin(c / a);
3703         }
3704
3705         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3706     },
3707
3708
3709     elasticOut: function (t, b, c, d, a, p) {
3710         if (t == 0) {
3711             return b;
3712         }
3713         if ((t /= d) == 1) {
3714             return b + c;
3715         }
3716         if (!p) {
3717             p = d * .3;
3718         }
3719
3720         if (!a || a < Math.abs(c)) {
3721             a = c;
3722             var s = p / 4;
3723         }
3724         else {
3725             var s = p / (2 * Math.PI) * Math.asin(c / a);
3726         }
3727
3728         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3729     },
3730
3731
3732     elasticBoth: function (t, b, c, d, a, p) {
3733         if (t == 0) {
3734             return b;
3735         }
3736
3737         if ((t /= d / 2) == 2) {
3738             return b + c;
3739         }
3740
3741         if (!p) {
3742             p = d * (.3 * 1.5);
3743         }
3744
3745         if (!a || a < Math.abs(c)) {
3746             a = c;
3747             var s = p / 4;
3748         }
3749         else {
3750             var s = p / (2 * Math.PI) * Math.asin(c / a);
3751         }
3752
3753         if (t < 1) {
3754             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3755                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3756         }
3757         return a * Math.pow(2, -10 * (t -= 1)) *
3758                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3759     },
3760
3761
3762
3763     backIn: function (t, b, c, d, s) {
3764         if (typeof s == 'undefined') {
3765             s = 1.70158;
3766         }
3767         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3768     },
3769
3770
3771     backOut: function (t, b, c, d, s) {
3772         if (typeof s == 'undefined') {
3773             s = 1.70158;
3774         }
3775         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3776     },
3777
3778
3779     backBoth: function (t, b, c, d, s) {
3780         if (typeof s == 'undefined') {
3781             s = 1.70158;
3782         }
3783
3784         if ((t /= d / 2 ) < 1) {
3785             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3786         }
3787         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3788     },
3789
3790
3791     bounceIn: function (t, b, c, d) {
3792         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3793     },
3794
3795
3796     bounceOut: function (t, b, c, d) {
3797         if ((t /= d) < (1 / 2.75)) {
3798             return c * (7.5625 * t * t) + b;
3799         } else if (t < (2 / 2.75)) {
3800             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3801         } else if (t < (2.5 / 2.75)) {
3802             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3803         }
3804         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3805     },
3806
3807
3808     bounceBoth: function (t, b, c, d) {
3809         if (t < d / 2) {
3810             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3811         }
3812         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3813     }
3814 };/*
3815  * Portions of this file are based on pieces of Yahoo User Interface Library
3816  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3817  * YUI licensed under the BSD License:
3818  * http://developer.yahoo.net/yui/license.txt
3819  * <script type="text/javascript">
3820  *
3821  */
3822     (function() {
3823         Roo.lib.Motion = function(el, attributes, duration, method) {
3824             if (el) {
3825                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3826             }
3827         };
3828
3829         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3830
3831
3832         var Y = Roo.lib;
3833         var superclass = Y.Motion.superclass;
3834         var proto = Y.Motion.prototype;
3835
3836         proto.toString = function() {
3837             var el = this.getEl();
3838             var id = el.id || el.tagName;
3839             return ("Motion " + id);
3840         };
3841
3842         proto.patterns.points = /^points$/i;
3843
3844         proto.setAttribute = function(attr, val, unit) {
3845             if (this.patterns.points.test(attr)) {
3846                 unit = unit || 'px';
3847                 superclass.setAttribute.call(this, 'left', val[0], unit);
3848                 superclass.setAttribute.call(this, 'top', val[1], unit);
3849             } else {
3850                 superclass.setAttribute.call(this, attr, val, unit);
3851             }
3852         };
3853
3854         proto.getAttribute = function(attr) {
3855             if (this.patterns.points.test(attr)) {
3856                 var val = [
3857                         superclass.getAttribute.call(this, 'left'),
3858                         superclass.getAttribute.call(this, 'top')
3859                         ];
3860             } else {
3861                 val = superclass.getAttribute.call(this, attr);
3862             }
3863
3864             return val;
3865         };
3866
3867         proto.doMethod = function(attr, start, end) {
3868             var val = null;
3869
3870             if (this.patterns.points.test(attr)) {
3871                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3872                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3873             } else {
3874                 val = superclass.doMethod.call(this, attr, start, end);
3875             }
3876             return val;
3877         };
3878
3879         proto.setRuntimeAttribute = function(attr) {
3880             if (this.patterns.points.test(attr)) {
3881                 var el = this.getEl();
3882                 var attributes = this.attributes;
3883                 var start;
3884                 var control = attributes['points']['control'] || [];
3885                 var end;
3886                 var i, len;
3887
3888                 if (control.length > 0 && !(control[0] instanceof Array)) {
3889                     control = [control];
3890                 } else {
3891                     var tmp = [];
3892                     for (i = 0,len = control.length; i < len; ++i) {
3893                         tmp[i] = control[i];
3894                     }
3895                     control = tmp;
3896                 }
3897
3898                 Roo.fly(el).position();
3899
3900                 if (isset(attributes['points']['from'])) {
3901                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3902                 }
3903                 else {
3904                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3905                 }
3906
3907                 start = this.getAttribute('points');
3908
3909
3910                 if (isset(attributes['points']['to'])) {
3911                     end = translateValues.call(this, attributes['points']['to'], start);
3912
3913                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3914                     for (i = 0,len = control.length; i < len; ++i) {
3915                         control[i] = translateValues.call(this, control[i], start);
3916                     }
3917
3918
3919                 } else if (isset(attributes['points']['by'])) {
3920                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3921
3922                     for (i = 0,len = control.length; i < len; ++i) {
3923                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3924                     }
3925                 }
3926
3927                 this.runtimeAttributes[attr] = [start];
3928
3929                 if (control.length > 0) {
3930                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3931                 }
3932
3933                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3934             }
3935             else {
3936                 superclass.setRuntimeAttribute.call(this, attr);
3937             }
3938         };
3939
3940         var translateValues = function(val, start) {
3941             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3942             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3943
3944             return val;
3945         };
3946
3947         var isset = function(prop) {
3948             return (typeof prop !== 'undefined');
3949         };
3950     })();
3951 /*
3952  * Portions of this file are based on pieces of Yahoo User Interface Library
3953  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3954  * YUI licensed under the BSD License:
3955  * http://developer.yahoo.net/yui/license.txt
3956  * <script type="text/javascript">
3957  *
3958  */
3959     (function() {
3960         Roo.lib.Scroll = function(el, attributes, duration, method) {
3961             if (el) {
3962                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3963             }
3964         };
3965
3966         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3967
3968
3969         var Y = Roo.lib;
3970         var superclass = Y.Scroll.superclass;
3971         var proto = Y.Scroll.prototype;
3972
3973         proto.toString = function() {
3974             var el = this.getEl();
3975             var id = el.id || el.tagName;
3976             return ("Scroll " + id);
3977         };
3978
3979         proto.doMethod = function(attr, start, end) {
3980             var val = null;
3981
3982             if (attr == 'scroll') {
3983                 val = [
3984                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3985                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3986                         ];
3987
3988             } else {
3989                 val = superclass.doMethod.call(this, attr, start, end);
3990             }
3991             return val;
3992         };
3993
3994         proto.getAttribute = function(attr) {
3995             var val = null;
3996             var el = this.getEl();
3997
3998             if (attr == 'scroll') {
3999                 val = [ el.scrollLeft, el.scrollTop ];
4000             } else {
4001                 val = superclass.getAttribute.call(this, attr);
4002             }
4003
4004             return val;
4005         };
4006
4007         proto.setAttribute = function(attr, val, unit) {
4008             var el = this.getEl();
4009
4010             if (attr == 'scroll') {
4011                 el.scrollLeft = val[0];
4012                 el.scrollTop = val[1];
4013             } else {
4014                 superclass.setAttribute.call(this, attr, val, unit);
4015             }
4016         };
4017     })();
4018 /*
4019  * Based on:
4020  * Ext JS Library 1.1.1
4021  * Copyright(c) 2006-2007, Ext JS, LLC.
4022  *
4023  * Originally Released Under LGPL - original licence link has changed is not relivant.
4024  *
4025  * Fork - LGPL
4026  * <script type="text/javascript">
4027  */
4028  
4029
4030 /**
4031  * @class Roo.DomHelper
4032  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4033  * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4034  * @singleton
4035  */
4036 Roo.DomHelper = function(){
4037     var tempTableEl = null;
4038     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4039     var tableRe = /^table|tbody|tr|td$/i;
4040     var xmlns = {};
4041     // build as innerHTML where available
4042     /** @ignore */
4043     var createHtml = function(o){
4044         if(typeof o == 'string'){
4045             return o;
4046         }
4047         var b = "";
4048         if(!o.tag){
4049             o.tag = "div";
4050         }
4051         b += "<" + o.tag;
4052         for(var attr in o){
4053             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4054             if(attr == "style"){
4055                 var s = o["style"];
4056                 if(typeof s == "function"){
4057                     s = s.call();
4058                 }
4059                 if(typeof s == "string"){
4060                     b += ' style="' + s + '"';
4061                 }else if(typeof s == "object"){
4062                     b += ' style="';
4063                     for(var key in s){
4064                         if(typeof s[key] != "function"){
4065                             b += key + ":" + s[key] + ";";
4066                         }
4067                     }
4068                     b += '"';
4069                 }
4070             }else{
4071                 if(attr == "cls"){
4072                     b += ' class="' + o["cls"] + '"';
4073                 }else if(attr == "htmlFor"){
4074                     b += ' for="' + o["htmlFor"] + '"';
4075                 }else{
4076                     b += " " + attr + '="' + o[attr] + '"';
4077                 }
4078             }
4079         }
4080         if(emptyTags.test(o.tag)){
4081             b += "/>";
4082         }else{
4083             b += ">";
4084             var cn = o.children || o.cn;
4085             if(cn){
4086                 //http://bugs.kde.org/show_bug.cgi?id=71506
4087                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4088                     for(var i = 0, len = cn.length; i < len; i++) {
4089                         b += createHtml(cn[i], b);
4090                     }
4091                 }else{
4092                     b += createHtml(cn, b);
4093                 }
4094             }
4095             if(o.html){
4096                 b += o.html;
4097             }
4098             b += "</" + o.tag + ">";
4099         }
4100         return b;
4101     };
4102
4103     // build as dom
4104     /** @ignore */
4105     var createDom = function(o, parentNode){
4106          
4107         // defininition craeted..
4108         var ns = false;
4109         if (o.ns && o.ns != 'html') {
4110                
4111             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4112                 xmlns[o.ns] = o.xmlns;
4113                 ns = o.xmlns;
4114             }
4115             if (typeof(xmlns[o.ns]) == 'undefined') {
4116                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4117             }
4118             ns = xmlns[o.ns];
4119         }
4120         
4121         
4122         if (typeof(o) == 'string') {
4123             return parentNode.appendChild(document.createTextNode(o));
4124         }
4125         o.tag = o.tag || div;
4126         if (o.ns && Roo.isIE) {
4127             ns = false;
4128             o.tag = o.ns + ':' + o.tag;
4129             
4130         }
4131         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4132         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4133         for(var attr in o){
4134             
4135             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4136                     attr == "style" || typeof o[attr] == "function") continue;
4137                     
4138             if(attr=="cls" && Roo.isIE){
4139                 el.className = o["cls"];
4140             }else{
4141                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4142                 else el[attr] = o[attr];
4143             }
4144         }
4145         Roo.DomHelper.applyStyles(el, o.style);
4146         var cn = o.children || o.cn;
4147         if(cn){
4148             //http://bugs.kde.org/show_bug.cgi?id=71506
4149              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4150                 for(var i = 0, len = cn.length; i < len; i++) {
4151                     createDom(cn[i], el);
4152                 }
4153             }else{
4154                 createDom(cn, el);
4155             }
4156         }
4157         if(o.html){
4158             el.innerHTML = o.html;
4159         }
4160         if(parentNode){
4161            parentNode.appendChild(el);
4162         }
4163         return el;
4164     };
4165
4166     var ieTable = function(depth, s, h, e){
4167         tempTableEl.innerHTML = [s, h, e].join('');
4168         var i = -1, el = tempTableEl;
4169         while(++i < depth){
4170             el = el.firstChild;
4171         }
4172         return el;
4173     };
4174
4175     // kill repeat to save bytes
4176     var ts = '<table>',
4177         te = '</table>',
4178         tbs = ts+'<tbody>',
4179         tbe = '</tbody>'+te,
4180         trs = tbs + '<tr>',
4181         tre = '</tr>'+tbe;
4182
4183     /**
4184      * @ignore
4185      * Nasty code for IE's broken table implementation
4186      */
4187     var insertIntoTable = function(tag, where, el, html){
4188         if(!tempTableEl){
4189             tempTableEl = document.createElement('div');
4190         }
4191         var node;
4192         var before = null;
4193         if(tag == 'td'){
4194             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4195                 return;
4196             }
4197             if(where == 'beforebegin'){
4198                 before = el;
4199                 el = el.parentNode;
4200             } else{
4201                 before = el.nextSibling;
4202                 el = el.parentNode;
4203             }
4204             node = ieTable(4, trs, html, tre);
4205         }
4206         else if(tag == 'tr'){
4207             if(where == 'beforebegin'){
4208                 before = el;
4209                 el = el.parentNode;
4210                 node = ieTable(3, tbs, html, tbe);
4211             } else if(where == 'afterend'){
4212                 before = el.nextSibling;
4213                 el = el.parentNode;
4214                 node = ieTable(3, tbs, html, tbe);
4215             } else{ // INTO a TR
4216                 if(where == 'afterbegin'){
4217                     before = el.firstChild;
4218                 }
4219                 node = ieTable(4, trs, html, tre);
4220             }
4221         } else if(tag == 'tbody'){
4222             if(where == 'beforebegin'){
4223                 before = el;
4224                 el = el.parentNode;
4225                 node = ieTable(2, ts, html, te);
4226             } else if(where == 'afterend'){
4227                 before = el.nextSibling;
4228                 el = el.parentNode;
4229                 node = ieTable(2, ts, html, te);
4230             } else{
4231                 if(where == 'afterbegin'){
4232                     before = el.firstChild;
4233                 }
4234                 node = ieTable(3, tbs, html, tbe);
4235             }
4236         } else{ // TABLE
4237             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4238                 return;
4239             }
4240             if(where == 'afterbegin'){
4241                 before = el.firstChild;
4242             }
4243             node = ieTable(2, ts, html, te);
4244         }
4245         el.insertBefore(node, before);
4246         return node;
4247     };
4248
4249     return {
4250     /** True to force the use of DOM instead of html fragments @type Boolean */
4251     useDom : false,
4252
4253     /**
4254      * Returns the markup for the passed Element(s) config
4255      * @param {Object} o The Dom object spec (and children)
4256      * @return {String}
4257      */
4258     markup : function(o){
4259         return createHtml(o);
4260     },
4261
4262     /**
4263      * Applies a style specification to an element
4264      * @param {String/HTMLElement} el The element to apply styles to
4265      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4266      * a function which returns such a specification.
4267      */
4268     applyStyles : function(el, styles){
4269         if(styles){
4270            el = Roo.fly(el);
4271            if(typeof styles == "string"){
4272                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4273                var matches;
4274                while ((matches = re.exec(styles)) != null){
4275                    el.setStyle(matches[1], matches[2]);
4276                }
4277            }else if (typeof styles == "object"){
4278                for (var style in styles){
4279                   el.setStyle(style, styles[style]);
4280                }
4281            }else if (typeof styles == "function"){
4282                 Roo.DomHelper.applyStyles(el, styles.call());
4283            }
4284         }
4285     },
4286
4287     /**
4288      * Inserts an HTML fragment into the Dom
4289      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4290      * @param {HTMLElement} el The context element
4291      * @param {String} html The HTML fragmenet
4292      * @return {HTMLElement} The new node
4293      */
4294     insertHtml : function(where, el, html){
4295         where = where.toLowerCase();
4296         if(el.insertAdjacentHTML){
4297             if(tableRe.test(el.tagName)){
4298                 var rs;
4299                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4300                     return rs;
4301                 }
4302             }
4303             switch(where){
4304                 case "beforebegin":
4305                     el.insertAdjacentHTML('BeforeBegin', html);
4306                     return el.previousSibling;
4307                 case "afterbegin":
4308                     el.insertAdjacentHTML('AfterBegin', html);
4309                     return el.firstChild;
4310                 case "beforeend":
4311                     el.insertAdjacentHTML('BeforeEnd', html);
4312                     return el.lastChild;
4313                 case "afterend":
4314                     el.insertAdjacentHTML('AfterEnd', html);
4315                     return el.nextSibling;
4316             }
4317             throw 'Illegal insertion point -> "' + where + '"';
4318         }
4319         var range = el.ownerDocument.createRange();
4320         var frag;
4321         switch(where){
4322              case "beforebegin":
4323                 range.setStartBefore(el);
4324                 frag = range.createContextualFragment(html);
4325                 el.parentNode.insertBefore(frag, el);
4326                 return el.previousSibling;
4327              case "afterbegin":
4328                 if(el.firstChild){
4329                     range.setStartBefore(el.firstChild);
4330                     frag = range.createContextualFragment(html);
4331                     el.insertBefore(frag, el.firstChild);
4332                     return el.firstChild;
4333                 }else{
4334                     el.innerHTML = html;
4335                     return el.firstChild;
4336                 }
4337             case "beforeend":
4338                 if(el.lastChild){
4339                     range.setStartAfter(el.lastChild);
4340                     frag = range.createContextualFragment(html);
4341                     el.appendChild(frag);
4342                     return el.lastChild;
4343                 }else{
4344                     el.innerHTML = html;
4345                     return el.lastChild;
4346                 }
4347             case "afterend":
4348                 range.setStartAfter(el);
4349                 frag = range.createContextualFragment(html);
4350                 el.parentNode.insertBefore(frag, el.nextSibling);
4351                 return el.nextSibling;
4352             }
4353             throw 'Illegal insertion point -> "' + where + '"';
4354     },
4355
4356     /**
4357      * Creates new Dom element(s) and inserts them before el
4358      * @param {String/HTMLElement/Element} el The context element
4359      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4360      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4361      * @return {HTMLElement/Roo.Element} The new node
4362      */
4363     insertBefore : function(el, o, returnElement){
4364         return this.doInsert(el, o, returnElement, "beforeBegin");
4365     },
4366
4367     /**
4368      * Creates new Dom element(s) and inserts them after el
4369      * @param {String/HTMLElement/Element} el The context element
4370      * @param {Object} o The Dom object spec (and children)
4371      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4372      * @return {HTMLElement/Roo.Element} The new node
4373      */
4374     insertAfter : function(el, o, returnElement){
4375         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4376     },
4377
4378     /**
4379      * Creates new Dom element(s) and inserts them as the first child of el
4380      * @param {String/HTMLElement/Element} el The context element
4381      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4382      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4383      * @return {HTMLElement/Roo.Element} The new node
4384      */
4385     insertFirst : function(el, o, returnElement){
4386         return this.doInsert(el, o, returnElement, "afterBegin");
4387     },
4388
4389     // private
4390     doInsert : function(el, o, returnElement, pos, sibling){
4391         el = Roo.getDom(el);
4392         var newNode;
4393         if(this.useDom || o.ns){
4394             newNode = createDom(o, null);
4395             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4396         }else{
4397             var html = createHtml(o);
4398             newNode = this.insertHtml(pos, el, html);
4399         }
4400         return returnElement ? Roo.get(newNode, true) : newNode;
4401     },
4402
4403     /**
4404      * Creates new Dom element(s) and appends them to el
4405      * @param {String/HTMLElement/Element} el The context element
4406      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4407      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4408      * @return {HTMLElement/Roo.Element} The new node
4409      */
4410     append : function(el, o, returnElement){
4411         el = Roo.getDom(el);
4412         var newNode;
4413         if(this.useDom || o.ns){
4414             newNode = createDom(o, null);
4415             el.appendChild(newNode);
4416         }else{
4417             var html = createHtml(o);
4418             newNode = this.insertHtml("beforeEnd", el, html);
4419         }
4420         return returnElement ? Roo.get(newNode, true) : newNode;
4421     },
4422
4423     /**
4424      * Creates new Dom element(s) and overwrites the contents of el with them
4425      * @param {String/HTMLElement/Element} el The context element
4426      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4427      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4428      * @return {HTMLElement/Roo.Element} The new node
4429      */
4430     overwrite : function(el, o, returnElement){
4431         el = Roo.getDom(el);
4432         if (o.ns) {
4433           
4434             while (el.childNodes.length) {
4435                 el.removeChild(el.firstChild);
4436             }
4437             createDom(o, el);
4438         } else {
4439             el.innerHTML = createHtml(o);   
4440         }
4441         
4442         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4443     },
4444
4445     /**
4446      * Creates a new Roo.DomHelper.Template from the Dom object spec
4447      * @param {Object} o The Dom object spec (and children)
4448      * @return {Roo.DomHelper.Template} The new template
4449      */
4450     createTemplate : function(o){
4451         var html = createHtml(o);
4452         return new Roo.Template(html);
4453     }
4454     };
4455 }();
4456 /*
4457  * Based on:
4458  * Ext JS Library 1.1.1
4459  * Copyright(c) 2006-2007, Ext JS, LLC.
4460  *
4461  * Originally Released Under LGPL - original licence link has changed is not relivant.
4462  *
4463  * Fork - LGPL
4464  * <script type="text/javascript">
4465  */
4466  
4467 /**
4468 * @class Roo.Template
4469 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4470 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4471 * Usage:
4472 <pre><code>
4473 var t = new Roo.Template({
4474     html :  '&lt;div name="{id}"&gt;' + 
4475         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4476         '&lt;/div&gt;',
4477     myformat: function (value, allValues) {
4478         return 'XX' + value;
4479     }
4480 });
4481 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4482 </code></pre>
4483 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
4484 * @constructor
4485 * @param {Object} cfg - Configuration object.
4486 */
4487 Roo.Template = function(cfg){
4488     // BC!
4489     if(cfg instanceof Array){
4490         cfg = cfg.join("");
4491     }else if(arguments.length > 1){
4492         cfg = Array.prototype.join.call(arguments, "");
4493     }
4494     
4495     
4496     if (typeof(cfg) == 'object') {
4497         Roo.apply(this,cfg)
4498     } else {
4499         // bc
4500         this.html = cfg;
4501     }
4502     
4503     
4504 };
4505 Roo.Template.prototype = {
4506     
4507     /**
4508      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4509      */
4510     html : '',
4511     /**
4512      * Returns an HTML fragment of this template with the specified values applied.
4513      * @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'})
4514      * @return {String} The HTML fragment
4515      */
4516     applyTemplate : function(values){
4517         try {
4518             
4519             if(this.compiled){
4520                 return this.compiled(values);
4521             }
4522             var useF = this.disableFormats !== true;
4523             var fm = Roo.util.Format, tpl = this;
4524             var fn = function(m, name, format, args){
4525                 if(format && useF){
4526                     if(format.substr(0, 5) == "this."){
4527                         return tpl.call(format.substr(5), values[name], values);
4528                     }else{
4529                         if(args){
4530                             // quoted values are required for strings in compiled templates, 
4531                             // but for non compiled we need to strip them
4532                             // quoted reversed for jsmin
4533                             var re = /^\s*['"](.*)["']\s*$/;
4534                             args = args.split(',');
4535                             for(var i = 0, len = args.length; i < len; i++){
4536                                 args[i] = args[i].replace(re, "$1");
4537                             }
4538                             args = [values[name]].concat(args);
4539                         }else{
4540                             args = [values[name]];
4541                         }
4542                         return fm[format].apply(fm, args);
4543                     }
4544                 }else{
4545                     return values[name] !== undefined ? values[name] : "";
4546                 }
4547             };
4548             return this.html.replace(this.re, fn);
4549         } catch (e) {
4550             Roo.log(e);
4551             throw e;
4552         }
4553          
4554     },
4555     
4556     /**
4557      * Sets the HTML used as the template and optionally compiles it.
4558      * @param {String} html
4559      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4560      * @return {Roo.Template} this
4561      */
4562     set : function(html, compile){
4563         this.html = html;
4564         this.compiled = null;
4565         if(compile){
4566             this.compile();
4567         }
4568         return this;
4569     },
4570     
4571     /**
4572      * True to disable format functions (defaults to false)
4573      * @type Boolean
4574      */
4575     disableFormats : false,
4576     
4577     /**
4578     * The regular expression used to match template variables 
4579     * @type RegExp
4580     * @property 
4581     */
4582     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4583     
4584     /**
4585      * Compiles the template into an internal function, eliminating the RegEx overhead.
4586      * @return {Roo.Template} this
4587      */
4588     compile : function(){
4589         var fm = Roo.util.Format;
4590         var useF = this.disableFormats !== true;
4591         var sep = Roo.isGecko ? "+" : ",";
4592         var fn = function(m, name, format, args){
4593             if(format && useF){
4594                 args = args ? ',' + args : "";
4595                 if(format.substr(0, 5) != "this."){
4596                     format = "fm." + format + '(';
4597                 }else{
4598                     format = 'this.call("'+ format.substr(5) + '", ';
4599                     args = ", values";
4600                 }
4601             }else{
4602                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4603             }
4604             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4605         };
4606         var body;
4607         // branched to use + in gecko and [].join() in others
4608         if(Roo.isGecko){
4609             body = "this.compiled = function(values){ return '" +
4610                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4611                     "';};";
4612         }else{
4613             body = ["this.compiled = function(values){ return ['"];
4614             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4615             body.push("'].join('');};");
4616             body = body.join('');
4617         }
4618         /**
4619          * eval:var:values
4620          * eval:var:fm
4621          */
4622         eval(body);
4623         return this;
4624     },
4625     
4626     // private function used to call members
4627     call : function(fnName, value, allValues){
4628         return this[fnName](value, allValues);
4629     },
4630     
4631     /**
4632      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4633      * @param {String/HTMLElement/Roo.Element} el The context element
4634      * @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'})
4635      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4636      * @return {HTMLElement/Roo.Element} The new node or Element
4637      */
4638     insertFirst: function(el, values, returnElement){
4639         return this.doInsert('afterBegin', el, values, returnElement);
4640     },
4641
4642     /**
4643      * Applies the supplied values to the template and inserts the new node(s) before el.
4644      * @param {String/HTMLElement/Roo.Element} el The context element
4645      * @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'})
4646      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4647      * @return {HTMLElement/Roo.Element} The new node or Element
4648      */
4649     insertBefore: function(el, values, returnElement){
4650         return this.doInsert('beforeBegin', el, values, returnElement);
4651     },
4652
4653     /**
4654      * Applies the supplied values to the template and inserts the new node(s) after el.
4655      * @param {String/HTMLElement/Roo.Element} el The context element
4656      * @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'})
4657      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4658      * @return {HTMLElement/Roo.Element} The new node or Element
4659      */
4660     insertAfter : function(el, values, returnElement){
4661         return this.doInsert('afterEnd', el, values, returnElement);
4662     },
4663     
4664     /**
4665      * Applies the supplied values to the template and appends the new node(s) to el.
4666      * @param {String/HTMLElement/Roo.Element} el The context element
4667      * @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'})
4668      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4669      * @return {HTMLElement/Roo.Element} The new node or Element
4670      */
4671     append : function(el, values, returnElement){
4672         return this.doInsert('beforeEnd', el, values, returnElement);
4673     },
4674
4675     doInsert : function(where, el, values, returnEl){
4676         el = Roo.getDom(el);
4677         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4678         return returnEl ? Roo.get(newNode, true) : newNode;
4679     },
4680
4681     /**
4682      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4683      * @param {String/HTMLElement/Roo.Element} el The context element
4684      * @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'})
4685      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4686      * @return {HTMLElement/Roo.Element} The new node or Element
4687      */
4688     overwrite : function(el, values, returnElement){
4689         el = Roo.getDom(el);
4690         el.innerHTML = this.applyTemplate(values);
4691         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4692     }
4693 };
4694 /**
4695  * Alias for {@link #applyTemplate}
4696  * @method
4697  */
4698 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4699
4700 // backwards compat
4701 Roo.DomHelper.Template = Roo.Template;
4702
4703 /**
4704  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4705  * @param {String/HTMLElement} el A DOM element or its id
4706  * @returns {Roo.Template} The created template
4707  * @static
4708  */
4709 Roo.Template.from = function(el){
4710     el = Roo.getDom(el);
4711     return new Roo.Template(el.value || el.innerHTML);
4712 };/*
4713  * Based on:
4714  * Ext JS Library 1.1.1
4715  * Copyright(c) 2006-2007, Ext JS, LLC.
4716  *
4717  * Originally Released Under LGPL - original licence link has changed is not relivant.
4718  *
4719  * Fork - LGPL
4720  * <script type="text/javascript">
4721  */
4722  
4723
4724 /*
4725  * This is code is also distributed under MIT license for use
4726  * with jQuery and prototype JavaScript libraries.
4727  */
4728 /**
4729  * @class Roo.DomQuery
4730 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).
4731 <p>
4732 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>
4733
4734 <p>
4735 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.
4736 </p>
4737 <h4>Element Selectors:</h4>
4738 <ul class="list">
4739     <li> <b>*</b> any element</li>
4740     <li> <b>E</b> an element with the tag E</li>
4741     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4742     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4743     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4744     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4745 </ul>
4746 <h4>Attribute Selectors:</h4>
4747 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4748 <ul class="list">
4749     <li> <b>E[foo]</b> has an attribute "foo"</li>
4750     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4751     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4752     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4753     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4754     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4755     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4756 </ul>
4757 <h4>Pseudo Classes:</h4>
4758 <ul class="list">
4759     <li> <b>E:first-child</b> E is the first child of its parent</li>
4760     <li> <b>E:last-child</b> E is the last child of its parent</li>
4761     <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>
4762     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4763     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4764     <li> <b>E:only-child</b> E is the only child of its parent</li>
4765     <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>
4766     <li> <b>E:first</b> the first E in the resultset</li>
4767     <li> <b>E:last</b> the last E in the resultset</li>
4768     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4769     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4770     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4771     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4772     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4773     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4774     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4775     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4776     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4777 </ul>
4778 <h4>CSS Value Selectors:</h4>
4779 <ul class="list">
4780     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4781     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4782     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4783     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4784     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4785     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4786 </ul>
4787  * @singleton
4788  */
4789 Roo.DomQuery = function(){
4790     var cache = {}, simpleCache = {}, valueCache = {};
4791     var nonSpace = /\S/;
4792     var trimRe = /^\s+|\s+$/g;
4793     var tplRe = /\{(\d+)\}/g;
4794     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4795     var tagTokenRe = /^(#)?([\w-\*]+)/;
4796     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4797
4798     function child(p, index){
4799         var i = 0;
4800         var n = p.firstChild;
4801         while(n){
4802             if(n.nodeType == 1){
4803                if(++i == index){
4804                    return n;
4805                }
4806             }
4807             n = n.nextSibling;
4808         }
4809         return null;
4810     };
4811
4812     function next(n){
4813         while((n = n.nextSibling) && n.nodeType != 1);
4814         return n;
4815     };
4816
4817     function prev(n){
4818         while((n = n.previousSibling) && n.nodeType != 1);
4819         return n;
4820     };
4821
4822     function children(d){
4823         var n = d.firstChild, ni = -1;
4824             while(n){
4825                 var nx = n.nextSibling;
4826                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4827                     d.removeChild(n);
4828                 }else{
4829                     n.nodeIndex = ++ni;
4830                 }
4831                 n = nx;
4832             }
4833             return this;
4834         };
4835
4836     function byClassName(c, a, v){
4837         if(!v){
4838             return c;
4839         }
4840         var r = [], ri = -1, cn;
4841         for(var i = 0, ci; ci = c[i]; i++){
4842             if((' '+ci.className+' ').indexOf(v) != -1){
4843                 r[++ri] = ci;
4844             }
4845         }
4846         return r;
4847     };
4848
4849     function attrValue(n, attr){
4850         if(!n.tagName && typeof n.length != "undefined"){
4851             n = n[0];
4852         }
4853         if(!n){
4854             return null;
4855         }
4856         if(attr == "for"){
4857             return n.htmlFor;
4858         }
4859         if(attr == "class" || attr == "className"){
4860             return n.className;
4861         }
4862         return n.getAttribute(attr) || n[attr];
4863
4864     };
4865
4866     function getNodes(ns, mode, tagName){
4867         var result = [], ri = -1, cs;
4868         if(!ns){
4869             return result;
4870         }
4871         tagName = tagName || "*";
4872         if(typeof ns.getElementsByTagName != "undefined"){
4873             ns = [ns];
4874         }
4875         if(!mode){
4876             for(var i = 0, ni; ni = ns[i]; i++){
4877                 cs = ni.getElementsByTagName(tagName);
4878                 for(var j = 0, ci; ci = cs[j]; j++){
4879                     result[++ri] = ci;
4880                 }
4881             }
4882         }else if(mode == "/" || mode == ">"){
4883             var utag = tagName.toUpperCase();
4884             for(var i = 0, ni, cn; ni = ns[i]; i++){
4885                 cn = ni.children || ni.childNodes;
4886                 for(var j = 0, cj; cj = cn[j]; j++){
4887                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4888                         result[++ri] = cj;
4889                     }
4890                 }
4891             }
4892         }else if(mode == "+"){
4893             var utag = tagName.toUpperCase();
4894             for(var i = 0, n; n = ns[i]; i++){
4895                 while((n = n.nextSibling) && n.nodeType != 1);
4896                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4897                     result[++ri] = n;
4898                 }
4899             }
4900         }else if(mode == "~"){
4901             for(var i = 0, n; n = ns[i]; i++){
4902                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4903                 if(n){
4904                     result[++ri] = n;
4905                 }
4906             }
4907         }
4908         return result;
4909     };
4910
4911     function concat(a, b){
4912         if(b.slice){
4913             return a.concat(b);
4914         }
4915         for(var i = 0, l = b.length; i < l; i++){
4916             a[a.length] = b[i];
4917         }
4918         return a;
4919     }
4920
4921     function byTag(cs, tagName){
4922         if(cs.tagName || cs == document){
4923             cs = [cs];
4924         }
4925         if(!tagName){
4926             return cs;
4927         }
4928         var r = [], ri = -1;
4929         tagName = tagName.toLowerCase();
4930         for(var i = 0, ci; ci = cs[i]; i++){
4931             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4932                 r[++ri] = ci;
4933             }
4934         }
4935         return r;
4936     };
4937
4938     function byId(cs, attr, id){
4939         if(cs.tagName || cs == document){
4940             cs = [cs];
4941         }
4942         if(!id){
4943             return cs;
4944         }
4945         var r = [], ri = -1;
4946         for(var i = 0,ci; ci = cs[i]; i++){
4947             if(ci && ci.id == id){
4948                 r[++ri] = ci;
4949                 return r;
4950             }
4951         }
4952         return r;
4953     };
4954
4955     function byAttribute(cs, attr, value, op, custom){
4956         var r = [], ri = -1, st = custom=="{";
4957         var f = Roo.DomQuery.operators[op];
4958         for(var i = 0, ci; ci = cs[i]; i++){
4959             var a;
4960             if(st){
4961                 a = Roo.DomQuery.getStyle(ci, attr);
4962             }
4963             else if(attr == "class" || attr == "className"){
4964                 a = ci.className;
4965             }else if(attr == "for"){
4966                 a = ci.htmlFor;
4967             }else if(attr == "href"){
4968                 a = ci.getAttribute("href", 2);
4969             }else{
4970                 a = ci.getAttribute(attr);
4971             }
4972             if((f && f(a, value)) || (!f && a)){
4973                 r[++ri] = ci;
4974             }
4975         }
4976         return r;
4977     };
4978
4979     function byPseudo(cs, name, value){
4980         return Roo.DomQuery.pseudos[name](cs, value);
4981     };
4982
4983     // This is for IE MSXML which does not support expandos.
4984     // IE runs the same speed using setAttribute, however FF slows way down
4985     // and Safari completely fails so they need to continue to use expandos.
4986     var isIE = window.ActiveXObject ? true : false;
4987
4988     // this eval is stop the compressor from
4989     // renaming the variable to something shorter
4990     
4991     /** eval:var:batch */
4992     var batch = 30803; 
4993
4994     var key = 30803;
4995
4996     function nodupIEXml(cs){
4997         var d = ++key;
4998         cs[0].setAttribute("_nodup", d);
4999         var r = [cs[0]];
5000         for(var i = 1, len = cs.length; i < len; i++){
5001             var c = cs[i];
5002             if(!c.getAttribute("_nodup") != d){
5003                 c.setAttribute("_nodup", d);
5004                 r[r.length] = c;
5005             }
5006         }
5007         for(var i = 0, len = cs.length; i < len; i++){
5008             cs[i].removeAttribute("_nodup");
5009         }
5010         return r;
5011     }
5012
5013     function nodup(cs){
5014         if(!cs){
5015             return [];
5016         }
5017         var len = cs.length, c, i, r = cs, cj, ri = -1;
5018         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5019             return cs;
5020         }
5021         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5022             return nodupIEXml(cs);
5023         }
5024         var d = ++key;
5025         cs[0]._nodup = d;
5026         for(i = 1; c = cs[i]; i++){
5027             if(c._nodup != d){
5028                 c._nodup = d;
5029             }else{
5030                 r = [];
5031                 for(var j = 0; j < i; j++){
5032                     r[++ri] = cs[j];
5033                 }
5034                 for(j = i+1; cj = cs[j]; j++){
5035                     if(cj._nodup != d){
5036                         cj._nodup = d;
5037                         r[++ri] = cj;
5038                     }
5039                 }
5040                 return r;
5041             }
5042         }
5043         return r;
5044     }
5045
5046     function quickDiffIEXml(c1, c2){
5047         var d = ++key;
5048         for(var i = 0, len = c1.length; i < len; i++){
5049             c1[i].setAttribute("_qdiff", d);
5050         }
5051         var r = [];
5052         for(var i = 0, len = c2.length; i < len; i++){
5053             if(c2[i].getAttribute("_qdiff") != d){
5054                 r[r.length] = c2[i];
5055             }
5056         }
5057         for(var i = 0, len = c1.length; i < len; i++){
5058            c1[i].removeAttribute("_qdiff");
5059         }
5060         return r;
5061     }
5062
5063     function quickDiff(c1, c2){
5064         var len1 = c1.length;
5065         if(!len1){
5066             return c2;
5067         }
5068         if(isIE && c1[0].selectSingleNode){
5069             return quickDiffIEXml(c1, c2);
5070         }
5071         var d = ++key;
5072         for(var i = 0; i < len1; i++){
5073             c1[i]._qdiff = d;
5074         }
5075         var r = [];
5076         for(var i = 0, len = c2.length; i < len; i++){
5077             if(c2[i]._qdiff != d){
5078                 r[r.length] = c2[i];
5079             }
5080         }
5081         return r;
5082     }
5083
5084     function quickId(ns, mode, root, id){
5085         if(ns == root){
5086            var d = root.ownerDocument || root;
5087            return d.getElementById(id);
5088         }
5089         ns = getNodes(ns, mode, "*");
5090         return byId(ns, null, id);
5091     }
5092
5093     return {
5094         getStyle : function(el, name){
5095             return Roo.fly(el).getStyle(name);
5096         },
5097         /**
5098          * Compiles a selector/xpath query into a reusable function. The returned function
5099          * takes one parameter "root" (optional), which is the context node from where the query should start.
5100          * @param {String} selector The selector/xpath query
5101          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5102          * @return {Function}
5103          */
5104         compile : function(path, type){
5105             type = type || "select";
5106             
5107             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5108             var q = path, mode, lq;
5109             var tk = Roo.DomQuery.matchers;
5110             var tklen = tk.length;
5111             var mm;
5112
5113             // accept leading mode switch
5114             var lmode = q.match(modeRe);
5115             if(lmode && lmode[1]){
5116                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5117                 q = q.replace(lmode[1], "");
5118             }
5119             // strip leading slashes
5120             while(path.substr(0, 1)=="/"){
5121                 path = path.substr(1);
5122             }
5123
5124             while(q && lq != q){
5125                 lq = q;
5126                 var tm = q.match(tagTokenRe);
5127                 if(type == "select"){
5128                     if(tm){
5129                         if(tm[1] == "#"){
5130                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5131                         }else{
5132                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5133                         }
5134                         q = q.replace(tm[0], "");
5135                     }else if(q.substr(0, 1) != '@'){
5136                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5137                     }
5138                 }else{
5139                     if(tm){
5140                         if(tm[1] == "#"){
5141                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5142                         }else{
5143                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5144                         }
5145                         q = q.replace(tm[0], "");
5146                     }
5147                 }
5148                 while(!(mm = q.match(modeRe))){
5149                     var matched = false;
5150                     for(var j = 0; j < tklen; j++){
5151                         var t = tk[j];
5152                         var m = q.match(t.re);
5153                         if(m){
5154                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5155                                                     return m[i];
5156                                                 });
5157                             q = q.replace(m[0], "");
5158                             matched = true;
5159                             break;
5160                         }
5161                     }
5162                     // prevent infinite loop on bad selector
5163                     if(!matched){
5164                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5165                     }
5166                 }
5167                 if(mm[1]){
5168                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5169                     q = q.replace(mm[1], "");
5170                 }
5171             }
5172             fn[fn.length] = "return nodup(n);\n}";
5173             
5174              /** 
5175               * list of variables that need from compression as they are used by eval.
5176              *  eval:var:batch 
5177              *  eval:var:nodup
5178              *  eval:var:byTag
5179              *  eval:var:ById
5180              *  eval:var:getNodes
5181              *  eval:var:quickId
5182              *  eval:var:mode
5183              *  eval:var:root
5184              *  eval:var:n
5185              *  eval:var:byClassName
5186              *  eval:var:byPseudo
5187              *  eval:var:byAttribute
5188              *  eval:var:attrValue
5189              * 
5190              **/ 
5191             eval(fn.join(""));
5192             return f;
5193         },
5194
5195         /**
5196          * Selects a group of elements.
5197          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5198          * @param {Node} root (optional) The start of the query (defaults to document).
5199          * @return {Array}
5200          */
5201         select : function(path, root, type){
5202             if(!root || root == document){
5203                 root = document;
5204             }
5205             if(typeof root == "string"){
5206                 root = document.getElementById(root);
5207             }
5208             var paths = path.split(",");
5209             var results = [];
5210             for(var i = 0, len = paths.length; i < len; i++){
5211                 var p = paths[i].replace(trimRe, "");
5212                 if(!cache[p]){
5213                     cache[p] = Roo.DomQuery.compile(p);
5214                     if(!cache[p]){
5215                         throw p + " is not a valid selector";
5216                     }
5217                 }
5218                 var result = cache[p](root);
5219                 if(result && result != document){
5220                     results = results.concat(result);
5221                 }
5222             }
5223             if(paths.length > 1){
5224                 return nodup(results);
5225             }
5226             return results;
5227         },
5228
5229         /**
5230          * Selects a single element.
5231          * @param {String} selector The selector/xpath query
5232          * @param {Node} root (optional) The start of the query (defaults to document).
5233          * @return {Element}
5234          */
5235         selectNode : function(path, root){
5236             return Roo.DomQuery.select(path, root)[0];
5237         },
5238
5239         /**
5240          * Selects the value of a node, optionally replacing null with the defaultValue.
5241          * @param {String} selector The selector/xpath query
5242          * @param {Node} root (optional) The start of the query (defaults to document).
5243          * @param {String} defaultValue
5244          */
5245         selectValue : function(path, root, defaultValue){
5246             path = path.replace(trimRe, "");
5247             if(!valueCache[path]){
5248                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5249             }
5250             var n = valueCache[path](root);
5251             n = n[0] ? n[0] : n;
5252             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5253             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5254         },
5255
5256         /**
5257          * Selects the value of a node, parsing integers and floats.
5258          * @param {String} selector The selector/xpath query
5259          * @param {Node} root (optional) The start of the query (defaults to document).
5260          * @param {Number} defaultValue
5261          * @return {Number}
5262          */
5263         selectNumber : function(path, root, defaultValue){
5264             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5265             return parseFloat(v);
5266         },
5267
5268         /**
5269          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5270          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5271          * @param {String} selector The simple selector to test
5272          * @return {Boolean}
5273          */
5274         is : function(el, ss){
5275             if(typeof el == "string"){
5276                 el = document.getElementById(el);
5277             }
5278             var isArray = (el instanceof Array);
5279             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5280             return isArray ? (result.length == el.length) : (result.length > 0);
5281         },
5282
5283         /**
5284          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5285          * @param {Array} el An array of elements to filter
5286          * @param {String} selector The simple selector to test
5287          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5288          * the selector instead of the ones that match
5289          * @return {Array}
5290          */
5291         filter : function(els, ss, nonMatches){
5292             ss = ss.replace(trimRe, "");
5293             if(!simpleCache[ss]){
5294                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5295             }
5296             var result = simpleCache[ss](els);
5297             return nonMatches ? quickDiff(result, els) : result;
5298         },
5299
5300         /**
5301          * Collection of matching regular expressions and code snippets.
5302          */
5303         matchers : [{
5304                 re: /^\.([\w-]+)/,
5305                 select: 'n = byClassName(n, null, " {1} ");'
5306             }, {
5307                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5308                 select: 'n = byPseudo(n, "{1}", "{2}");'
5309             },{
5310                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5311                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5312             }, {
5313                 re: /^#([\w-]+)/,
5314                 select: 'n = byId(n, null, "{1}");'
5315             },{
5316                 re: /^@([\w-]+)/,
5317                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5318             }
5319         ],
5320
5321         /**
5322          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5323          * 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;.
5324          */
5325         operators : {
5326             "=" : function(a, v){
5327                 return a == v;
5328             },
5329             "!=" : function(a, v){
5330                 return a != v;
5331             },
5332             "^=" : function(a, v){
5333                 return a && a.substr(0, v.length) == v;
5334             },
5335             "$=" : function(a, v){
5336                 return a && a.substr(a.length-v.length) == v;
5337             },
5338             "*=" : function(a, v){
5339                 return a && a.indexOf(v) !== -1;
5340             },
5341             "%=" : function(a, v){
5342                 return (a % v) == 0;
5343             },
5344             "|=" : function(a, v){
5345                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5346             },
5347             "~=" : function(a, v){
5348                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5349             }
5350         },
5351
5352         /**
5353          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5354          * and the argument (if any) supplied in the selector.
5355          */
5356         pseudos : {
5357             "first-child" : function(c){
5358                 var r = [], ri = -1, n;
5359                 for(var i = 0, ci; ci = n = c[i]; i++){
5360                     while((n = n.previousSibling) && n.nodeType != 1);
5361                     if(!n){
5362                         r[++ri] = ci;
5363                     }
5364                 }
5365                 return r;
5366             },
5367
5368             "last-child" : function(c){
5369                 var r = [], ri = -1, n;
5370                 for(var i = 0, ci; ci = n = c[i]; i++){
5371                     while((n = n.nextSibling) && n.nodeType != 1);
5372                     if(!n){
5373                         r[++ri] = ci;
5374                     }
5375                 }
5376                 return r;
5377             },
5378
5379             "nth-child" : function(c, a) {
5380                 var r = [], ri = -1;
5381                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5382                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5383                 for(var i = 0, n; n = c[i]; i++){
5384                     var pn = n.parentNode;
5385                     if (batch != pn._batch) {
5386                         var j = 0;
5387                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5388                             if(cn.nodeType == 1){
5389                                cn.nodeIndex = ++j;
5390                             }
5391                         }
5392                         pn._batch = batch;
5393                     }
5394                     if (f == 1) {
5395                         if (l == 0 || n.nodeIndex == l){
5396                             r[++ri] = n;
5397                         }
5398                     } else if ((n.nodeIndex + l) % f == 0){
5399                         r[++ri] = n;
5400                     }
5401                 }
5402
5403                 return r;
5404             },
5405
5406             "only-child" : function(c){
5407                 var r = [], ri = -1;;
5408                 for(var i = 0, ci; ci = c[i]; i++){
5409                     if(!prev(ci) && !next(ci)){
5410                         r[++ri] = ci;
5411                     }
5412                 }
5413                 return r;
5414             },
5415
5416             "empty" : function(c){
5417                 var r = [], ri = -1;
5418                 for(var i = 0, ci; ci = c[i]; i++){
5419                     var cns = ci.childNodes, j = 0, cn, empty = true;
5420                     while(cn = cns[j]){
5421                         ++j;
5422                         if(cn.nodeType == 1 || cn.nodeType == 3){
5423                             empty = false;
5424                             break;
5425                         }
5426                     }
5427                     if(empty){
5428                         r[++ri] = ci;
5429                     }
5430                 }
5431                 return r;
5432             },
5433
5434             "contains" : function(c, v){
5435                 var r = [], ri = -1;
5436                 for(var i = 0, ci; ci = c[i]; i++){
5437                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5438                         r[++ri] = ci;
5439                     }
5440                 }
5441                 return r;
5442             },
5443
5444             "nodeValue" : function(c, v){
5445                 var r = [], ri = -1;
5446                 for(var i = 0, ci; ci = c[i]; i++){
5447                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5448                         r[++ri] = ci;
5449                     }
5450                 }
5451                 return r;
5452             },
5453
5454             "checked" : function(c){
5455                 var r = [], ri = -1;
5456                 for(var i = 0, ci; ci = c[i]; i++){
5457                     if(ci.checked == true){
5458                         r[++ri] = ci;
5459                     }
5460                 }
5461                 return r;
5462             },
5463
5464             "not" : function(c, ss){
5465                 return Roo.DomQuery.filter(c, ss, true);
5466             },
5467
5468             "odd" : function(c){
5469                 return this["nth-child"](c, "odd");
5470             },
5471
5472             "even" : function(c){
5473                 return this["nth-child"](c, "even");
5474             },
5475
5476             "nth" : function(c, a){
5477                 return c[a-1] || [];
5478             },
5479
5480             "first" : function(c){
5481                 return c[0] || [];
5482             },
5483
5484             "last" : function(c){
5485                 return c[c.length-1] || [];
5486             },
5487
5488             "has" : function(c, ss){
5489                 var s = Roo.DomQuery.select;
5490                 var r = [], ri = -1;
5491                 for(var i = 0, ci; ci = c[i]; i++){
5492                     if(s(ss, ci).length > 0){
5493                         r[++ri] = ci;
5494                     }
5495                 }
5496                 return r;
5497             },
5498
5499             "next" : function(c, ss){
5500                 var is = Roo.DomQuery.is;
5501                 var r = [], ri = -1;
5502                 for(var i = 0, ci; ci = c[i]; i++){
5503                     var n = next(ci);
5504                     if(n && is(n, ss)){
5505                         r[++ri] = ci;
5506                     }
5507                 }
5508                 return r;
5509             },
5510
5511             "prev" : function(c, ss){
5512                 var is = Roo.DomQuery.is;
5513                 var r = [], ri = -1;
5514                 for(var i = 0, ci; ci = c[i]; i++){
5515                     var n = prev(ci);
5516                     if(n && is(n, ss)){
5517                         r[++ri] = ci;
5518                     }
5519                 }
5520                 return r;
5521             }
5522         }
5523     };
5524 }();
5525
5526 /**
5527  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5528  * @param {String} path The selector/xpath query
5529  * @param {Node} root (optional) The start of the query (defaults to document).
5530  * @return {Array}
5531  * @member Roo
5532  * @method query
5533  */
5534 Roo.query = Roo.DomQuery.select;
5535 /*
5536  * Based on:
5537  * Ext JS Library 1.1.1
5538  * Copyright(c) 2006-2007, Ext JS, LLC.
5539  *
5540  * Originally Released Under LGPL - original licence link has changed is not relivant.
5541  *
5542  * Fork - LGPL
5543  * <script type="text/javascript">
5544  */
5545
5546 /**
5547  * @class Roo.util.Observable
5548  * Base class that provides a common interface for publishing events. Subclasses are expected to
5549  * to have a property "events" with all the events defined.<br>
5550  * For example:
5551  * <pre><code>
5552  Employee = function(name){
5553     this.name = name;
5554     this.addEvents({
5555         "fired" : true,
5556         "quit" : true
5557     });
5558  }
5559  Roo.extend(Employee, Roo.util.Observable);
5560 </code></pre>
5561  * @param {Object} config properties to use (incuding events / listeners)
5562  */
5563
5564 Roo.util.Observable = function(cfg){
5565     
5566     cfg = cfg|| {};
5567     this.addEvents(cfg.events || {});
5568     if (cfg.events) {
5569         delete cfg.events; // make sure
5570     }
5571      
5572     Roo.apply(this, cfg);
5573     
5574     if(this.listeners){
5575         this.on(this.listeners);
5576         delete this.listeners;
5577     }
5578 };
5579 Roo.util.Observable.prototype = {
5580     /** 
5581  * @cfg {Object} listeners  list of events and functions to call for this object, 
5582  * For example :
5583  * <pre><code>
5584     listeners :  { 
5585        'click' : function(e) {
5586            ..... 
5587         } ,
5588         .... 
5589     } 
5590   </code></pre>
5591  */
5592     
5593     
5594     /**
5595      * Fires the specified event with the passed parameters (minus the event name).
5596      * @param {String} eventName
5597      * @param {Object...} args Variable number of parameters are passed to handlers
5598      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5599      */
5600     fireEvent : function(){
5601         var ce = this.events[arguments[0].toLowerCase()];
5602         if(typeof ce == "object"){
5603             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5604         }else{
5605             return true;
5606         }
5607     },
5608
5609     // private
5610     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5611
5612     /**
5613      * Appends an event handler to this component
5614      * @param {String}   eventName The type of event to listen for
5615      * @param {Function} handler The method the event invokes
5616      * @param {Object}   scope (optional) The scope in which to execute the handler
5617      * function. The handler function's "this" context.
5618      * @param {Object}   options (optional) An object containing handler configuration
5619      * properties. This may contain any of the following properties:<ul>
5620      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5621      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5622      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5623      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5624      * by the specified number of milliseconds. If the event fires again within that time, the original
5625      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5626      * </ul><br>
5627      * <p>
5628      * <b>Combining Options</b><br>
5629      * Using the options argument, it is possible to combine different types of listeners:<br>
5630      * <br>
5631      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5632                 <pre><code>
5633                 el.on('click', this.onClick, this, {
5634                         single: true,
5635                 delay: 100,
5636                 forumId: 4
5637                 });
5638                 </code></pre>
5639      * <p>
5640      * <b>Attaching multiple handlers in 1 call</b><br>
5641      * The method also allows for a single argument to be passed which is a config object containing properties
5642      * which specify multiple handlers.
5643      * <pre><code>
5644                 el.on({
5645                         'click': {
5646                         fn: this.onClick,
5647                         scope: this,
5648                         delay: 100
5649                 }, 
5650                 'mouseover': {
5651                         fn: this.onMouseOver,
5652                         scope: this
5653                 },
5654                 'mouseout': {
5655                         fn: this.onMouseOut,
5656                         scope: this
5657                 }
5658                 });
5659                 </code></pre>
5660      * <p>
5661      * Or a shorthand syntax which passes the same scope object to all handlers:
5662         <pre><code>
5663                 el.on({
5664                         'click': this.onClick,
5665                 'mouseover': this.onMouseOver,
5666                 'mouseout': this.onMouseOut,
5667                 scope: this
5668                 });
5669                 </code></pre>
5670      */
5671     addListener : function(eventName, fn, scope, o){
5672         if(typeof eventName == "object"){
5673             o = eventName;
5674             for(var e in o){
5675                 if(this.filterOptRe.test(e)){
5676                     continue;
5677                 }
5678                 if(typeof o[e] == "function"){
5679                     // shared options
5680                     this.addListener(e, o[e], o.scope,  o);
5681                 }else{
5682                     // individual options
5683                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5684                 }
5685             }
5686             return;
5687         }
5688         o = (!o || typeof o == "boolean") ? {} : o;
5689         eventName = eventName.toLowerCase();
5690         var ce = this.events[eventName] || true;
5691         if(typeof ce == "boolean"){
5692             ce = new Roo.util.Event(this, eventName);
5693             this.events[eventName] = ce;
5694         }
5695         ce.addListener(fn, scope, o);
5696     },
5697
5698     /**
5699      * Removes a listener
5700      * @param {String}   eventName     The type of event to listen for
5701      * @param {Function} handler        The handler to remove
5702      * @param {Object}   scope  (optional) The scope (this object) for the handler
5703      */
5704     removeListener : function(eventName, fn, scope){
5705         var ce = this.events[eventName.toLowerCase()];
5706         if(typeof ce == "object"){
5707             ce.removeListener(fn, scope);
5708         }
5709     },
5710
5711     /**
5712      * Removes all listeners for this object
5713      */
5714     purgeListeners : function(){
5715         for(var evt in this.events){
5716             if(typeof this.events[evt] == "object"){
5717                  this.events[evt].clearListeners();
5718             }
5719         }
5720     },
5721
5722     relayEvents : function(o, events){
5723         var createHandler = function(ename){
5724             return function(){
5725                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5726             };
5727         };
5728         for(var i = 0, len = events.length; i < len; i++){
5729             var ename = events[i];
5730             if(!this.events[ename]){ this.events[ename] = true; };
5731             o.on(ename, createHandler(ename), this);
5732         }
5733     },
5734
5735     /**
5736      * Used to define events on this Observable
5737      * @param {Object} object The object with the events defined
5738      */
5739     addEvents : function(o){
5740         if(!this.events){
5741             this.events = {};
5742         }
5743         Roo.applyIf(this.events, o);
5744     },
5745
5746     /**
5747      * Checks to see if this object has any listeners for a specified event
5748      * @param {String} eventName The name of the event to check for
5749      * @return {Boolean} True if the event is being listened for, else false
5750      */
5751     hasListener : function(eventName){
5752         var e = this.events[eventName];
5753         return typeof e == "object" && e.listeners.length > 0;
5754     }
5755 };
5756 /**
5757  * Appends an event handler to this element (shorthand for addListener)
5758  * @param {String}   eventName     The type of event to listen for
5759  * @param {Function} handler        The method the event invokes
5760  * @param {Object}   scope (optional) The scope in which to execute the handler
5761  * function. The handler function's "this" context.
5762  * @param {Object}   options  (optional)
5763  * @method
5764  */
5765 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5766 /**
5767  * Removes a listener (shorthand for removeListener)
5768  * @param {String}   eventName     The type of event to listen for
5769  * @param {Function} handler        The handler to remove
5770  * @param {Object}   scope  (optional) The scope (this object) for the handler
5771  * @method
5772  */
5773 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5774
5775 /**
5776  * Starts capture on the specified Observable. All events will be passed
5777  * to the supplied function with the event name + standard signature of the event
5778  * <b>before</b> the event is fired. If the supplied function returns false,
5779  * the event will not fire.
5780  * @param {Observable} o The Observable to capture
5781  * @param {Function} fn The function to call
5782  * @param {Object} scope (optional) The scope (this object) for the fn
5783  * @static
5784  */
5785 Roo.util.Observable.capture = function(o, fn, scope){
5786     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5787 };
5788
5789 /**
5790  * Removes <b>all</b> added captures from the Observable.
5791  * @param {Observable} o The Observable to release
5792  * @static
5793  */
5794 Roo.util.Observable.releaseCapture = function(o){
5795     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5796 };
5797
5798 (function(){
5799
5800     var createBuffered = function(h, o, scope){
5801         var task = new Roo.util.DelayedTask();
5802         return function(){
5803             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5804         };
5805     };
5806
5807     var createSingle = function(h, e, fn, scope){
5808         return function(){
5809             e.removeListener(fn, scope);
5810             return h.apply(scope, arguments);
5811         };
5812     };
5813
5814     var createDelayed = function(h, o, scope){
5815         return function(){
5816             var args = Array.prototype.slice.call(arguments, 0);
5817             setTimeout(function(){
5818                 h.apply(scope, args);
5819             }, o.delay || 10);
5820         };
5821     };
5822
5823     Roo.util.Event = function(obj, name){
5824         this.name = name;
5825         this.obj = obj;
5826         this.listeners = [];
5827     };
5828
5829     Roo.util.Event.prototype = {
5830         addListener : function(fn, scope, options){
5831             var o = options || {};
5832             scope = scope || this.obj;
5833             if(!this.isListening(fn, scope)){
5834                 var l = {fn: fn, scope: scope, options: o};
5835                 var h = fn;
5836                 if(o.delay){
5837                     h = createDelayed(h, o, scope);
5838                 }
5839                 if(o.single){
5840                     h = createSingle(h, this, fn, scope);
5841                 }
5842                 if(o.buffer){
5843                     h = createBuffered(h, o, scope);
5844                 }
5845                 l.fireFn = h;
5846                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5847                     this.listeners.push(l);
5848                 }else{
5849                     this.listeners = this.listeners.slice(0);
5850                     this.listeners.push(l);
5851                 }
5852             }
5853         },
5854
5855         findListener : function(fn, scope){
5856             scope = scope || this.obj;
5857             var ls = this.listeners;
5858             for(var i = 0, len = ls.length; i < len; i++){
5859                 var l = ls[i];
5860                 if(l.fn == fn && l.scope == scope){
5861                     return i;
5862                 }
5863             }
5864             return -1;
5865         },
5866
5867         isListening : function(fn, scope){
5868             return this.findListener(fn, scope) != -1;
5869         },
5870
5871         removeListener : function(fn, scope){
5872             var index;
5873             if((index = this.findListener(fn, scope)) != -1){
5874                 if(!this.firing){
5875                     this.listeners.splice(index, 1);
5876                 }else{
5877                     this.listeners = this.listeners.slice(0);
5878                     this.listeners.splice(index, 1);
5879                 }
5880                 return true;
5881             }
5882             return false;
5883         },
5884
5885         clearListeners : function(){
5886             this.listeners = [];
5887         },
5888
5889         fire : function(){
5890             var ls = this.listeners, scope, len = ls.length;
5891             if(len > 0){
5892                 this.firing = true;
5893                 var args = Array.prototype.slice.call(arguments, 0);
5894                 for(var i = 0; i < len; i++){
5895                     var l = ls[i];
5896                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5897                         this.firing = false;
5898                         return false;
5899                     }
5900                 }
5901                 this.firing = false;
5902             }
5903             return true;
5904         }
5905     };
5906 })();/*
5907  * Based on:
5908  * Ext JS Library 1.1.1
5909  * Copyright(c) 2006-2007, Ext JS, LLC.
5910  *
5911  * Originally Released Under LGPL - original licence link has changed is not relivant.
5912  *
5913  * Fork - LGPL
5914  * <script type="text/javascript">
5915  */
5916
5917 /**
5918  * @class Roo.EventManager
5919  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5920  * several useful events directly.
5921  * See {@link Roo.EventObject} for more details on normalized event objects.
5922  * @singleton
5923  */
5924 Roo.EventManager = function(){
5925     var docReadyEvent, docReadyProcId, docReadyState = false;
5926     var resizeEvent, resizeTask, textEvent, textSize;
5927     var E = Roo.lib.Event;
5928     var D = Roo.lib.Dom;
5929
5930
5931     var fireDocReady = function(){
5932         if(!docReadyState){
5933             docReadyState = true;
5934             Roo.isReady = true;
5935             if(docReadyProcId){
5936                 clearInterval(docReadyProcId);
5937             }
5938             if(Roo.isGecko || Roo.isOpera) {
5939                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5940             }
5941             if(Roo.isIE){
5942                 var defer = document.getElementById("ie-deferred-loader");
5943                 if(defer){
5944                     defer.onreadystatechange = null;
5945                     defer.parentNode.removeChild(defer);
5946                 }
5947             }
5948             if(docReadyEvent){
5949                 docReadyEvent.fire();
5950                 docReadyEvent.clearListeners();
5951             }
5952         }
5953     };
5954     
5955     var initDocReady = function(){
5956         docReadyEvent = new Roo.util.Event();
5957         if(Roo.isGecko || Roo.isOpera) {
5958             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5959         }else if(Roo.isIE){
5960             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5961             var defer = document.getElementById("ie-deferred-loader");
5962             defer.onreadystatechange = function(){
5963                 if(this.readyState == "complete"){
5964                     fireDocReady();
5965                 }
5966             };
5967         }else if(Roo.isSafari){ 
5968             docReadyProcId = setInterval(function(){
5969                 var rs = document.readyState;
5970                 if(rs == "complete") {
5971                     fireDocReady();     
5972                  }
5973             }, 10);
5974         }
5975         // no matter what, make sure it fires on load
5976         E.on(window, "load", fireDocReady);
5977     };
5978
5979     var createBuffered = function(h, o){
5980         var task = new Roo.util.DelayedTask(h);
5981         return function(e){
5982             // create new event object impl so new events don't wipe out properties
5983             e = new Roo.EventObjectImpl(e);
5984             task.delay(o.buffer, h, null, [e]);
5985         };
5986     };
5987
5988     var createSingle = function(h, el, ename, fn){
5989         return function(e){
5990             Roo.EventManager.removeListener(el, ename, fn);
5991             h(e);
5992         };
5993     };
5994
5995     var createDelayed = function(h, o){
5996         return function(e){
5997             // create new event object impl so new events don't wipe out properties
5998             e = new Roo.EventObjectImpl(e);
5999             setTimeout(function(){
6000                 h(e);
6001             }, o.delay || 10);
6002         };
6003     };
6004
6005     var listen = function(element, ename, opt, fn, scope){
6006         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6007         fn = fn || o.fn; scope = scope || o.scope;
6008         var el = Roo.getDom(element);
6009         if(!el){
6010             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6011         }
6012         var h = function(e){
6013             e = Roo.EventObject.setEvent(e);
6014             var t;
6015             if(o.delegate){
6016                 t = e.getTarget(o.delegate, el);
6017                 if(!t){
6018                     return;
6019                 }
6020             }else{
6021                 t = e.target;
6022             }
6023             if(o.stopEvent === true){
6024                 e.stopEvent();
6025             }
6026             if(o.preventDefault === true){
6027                e.preventDefault();
6028             }
6029             if(o.stopPropagation === true){
6030                 e.stopPropagation();
6031             }
6032
6033             if(o.normalized === false){
6034                 e = e.browserEvent;
6035             }
6036
6037             fn.call(scope || el, e, t, o);
6038         };
6039         if(o.delay){
6040             h = createDelayed(h, o);
6041         }
6042         if(o.single){
6043             h = createSingle(h, el, ename, fn);
6044         }
6045         if(o.buffer){
6046             h = createBuffered(h, o);
6047         }
6048         fn._handlers = fn._handlers || [];
6049         fn._handlers.push([Roo.id(el), ename, h]);
6050
6051         E.on(el, ename, h);
6052         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6053             el.addEventListener("DOMMouseScroll", h, false);
6054             E.on(window, 'unload', function(){
6055                 el.removeEventListener("DOMMouseScroll", h, false);
6056             });
6057         }
6058         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6059             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6060         }
6061         return h;
6062     };
6063
6064     var stopListening = function(el, ename, fn){
6065         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6066         if(hds){
6067             for(var i = 0, len = hds.length; i < len; i++){
6068                 var h = hds[i];
6069                 if(h[0] == id && h[1] == ename){
6070                     hd = h[2];
6071                     hds.splice(i, 1);
6072                     break;
6073                 }
6074             }
6075         }
6076         E.un(el, ename, hd);
6077         el = Roo.getDom(el);
6078         if(ename == "mousewheel" && el.addEventListener){
6079             el.removeEventListener("DOMMouseScroll", hd, false);
6080         }
6081         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6082             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6083         }
6084     };
6085
6086     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6087     
6088     var pub = {
6089         
6090         
6091         /** 
6092          * Fix for doc tools
6093          * @scope Roo.EventManager
6094          */
6095         
6096         
6097         /** 
6098          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6099          * object with a Roo.EventObject
6100          * @param {Function} fn        The method the event invokes
6101          * @param {Object}   scope    An object that becomes the scope of the handler
6102          * @param {boolean}  override If true, the obj passed in becomes
6103          *                             the execution scope of the listener
6104          * @return {Function} The wrapped function
6105          * @deprecated
6106          */
6107         wrap : function(fn, scope, override){
6108             return function(e){
6109                 Roo.EventObject.setEvent(e);
6110                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6111             };
6112         },
6113         
6114         /**
6115      * Appends an event handler to an element (shorthand for addListener)
6116      * @param {String/HTMLElement}   element        The html element or id to assign the
6117      * @param {String}   eventName The type of event to listen for
6118      * @param {Function} handler The method the event invokes
6119      * @param {Object}   scope (optional) The scope in which to execute the handler
6120      * function. The handler function's "this" context.
6121      * @param {Object}   options (optional) An object containing handler configuration
6122      * properties. This may contain any of the following properties:<ul>
6123      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6124      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6125      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6126      * <li>preventDefault {Boolean} True to prevent the default action</li>
6127      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6128      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6129      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6130      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6131      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6132      * by the specified number of milliseconds. If the event fires again within that time, the original
6133      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6134      * </ul><br>
6135      * <p>
6136      * <b>Combining Options</b><br>
6137      * Using the options argument, it is possible to combine different types of listeners:<br>
6138      * <br>
6139      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6140      * Code:<pre><code>
6141 el.on('click', this.onClick, this, {
6142     single: true,
6143     delay: 100,
6144     stopEvent : true,
6145     forumId: 4
6146 });</code></pre>
6147      * <p>
6148      * <b>Attaching multiple handlers in 1 call</b><br>
6149       * The method also allows for a single argument to be passed which is a config object containing properties
6150      * which specify multiple handlers.
6151      * <p>
6152      * Code:<pre><code>
6153 el.on({
6154     'click' : {
6155         fn: this.onClick
6156         scope: this,
6157         delay: 100
6158     },
6159     'mouseover' : {
6160         fn: this.onMouseOver
6161         scope: this
6162     },
6163     'mouseout' : {
6164         fn: this.onMouseOut
6165         scope: this
6166     }
6167 });</code></pre>
6168      * <p>
6169      * Or a shorthand syntax:<br>
6170      * Code:<pre><code>
6171 el.on({
6172     'click' : this.onClick,
6173     'mouseover' : this.onMouseOver,
6174     'mouseout' : this.onMouseOut
6175     scope: this
6176 });</code></pre>
6177      */
6178         addListener : function(element, eventName, fn, scope, options){
6179             if(typeof eventName == "object"){
6180                 var o = eventName;
6181                 for(var e in o){
6182                     if(propRe.test(e)){
6183                         continue;
6184                     }
6185                     if(typeof o[e] == "function"){
6186                         // shared options
6187                         listen(element, e, o, o[e], o.scope);
6188                     }else{
6189                         // individual options
6190                         listen(element, e, o[e]);
6191                     }
6192                 }
6193                 return;
6194             }
6195             return listen(element, eventName, options, fn, scope);
6196         },
6197         
6198         /**
6199          * Removes an event handler
6200          *
6201          * @param {String/HTMLElement}   element        The id or html element to remove the 
6202          *                             event from
6203          * @param {String}   eventName     The type of event
6204          * @param {Function} fn
6205          * @return {Boolean} True if a listener was actually removed
6206          */
6207         removeListener : function(element, eventName, fn){
6208             return stopListening(element, eventName, fn);
6209         },
6210         
6211         /**
6212          * Fires when the document is ready (before onload and before images are loaded). Can be 
6213          * accessed shorthanded Roo.onReady().
6214          * @param {Function} fn        The method the event invokes
6215          * @param {Object}   scope    An  object that becomes the scope of the handler
6216          * @param {boolean}  options
6217          */
6218         onDocumentReady : function(fn, scope, options){
6219             if(docReadyState){ // if it already fired
6220                 docReadyEvent.addListener(fn, scope, options);
6221                 docReadyEvent.fire();
6222                 docReadyEvent.clearListeners();
6223                 return;
6224             }
6225             if(!docReadyEvent){
6226                 initDocReady();
6227             }
6228             docReadyEvent.addListener(fn, scope, options);
6229         },
6230         
6231         /**
6232          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6233          * @param {Function} fn        The method the event invokes
6234          * @param {Object}   scope    An object that becomes the scope of the handler
6235          * @param {boolean}  options
6236          */
6237         onWindowResize : function(fn, scope, options){
6238             if(!resizeEvent){
6239                 resizeEvent = new Roo.util.Event();
6240                 resizeTask = new Roo.util.DelayedTask(function(){
6241                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6242                 });
6243                 E.on(window, "resize", function(){
6244                     if(Roo.isIE){
6245                         resizeTask.delay(50);
6246                     }else{
6247                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6248                     }
6249                 });
6250             }
6251             resizeEvent.addListener(fn, scope, options);
6252         },
6253
6254         /**
6255          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6256          * @param {Function} fn        The method the event invokes
6257          * @param {Object}   scope    An object that becomes the scope of the handler
6258          * @param {boolean}  options
6259          */
6260         onTextResize : function(fn, scope, options){
6261             if(!textEvent){
6262                 textEvent = new Roo.util.Event();
6263                 var textEl = new Roo.Element(document.createElement('div'));
6264                 textEl.dom.className = 'x-text-resize';
6265                 textEl.dom.innerHTML = 'X';
6266                 textEl.appendTo(document.body);
6267                 textSize = textEl.dom.offsetHeight;
6268                 setInterval(function(){
6269                     if(textEl.dom.offsetHeight != textSize){
6270                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6271                     }
6272                 }, this.textResizeInterval);
6273             }
6274             textEvent.addListener(fn, scope, options);
6275         },
6276
6277         /**
6278          * Removes the passed window resize listener.
6279          * @param {Function} fn        The method the event invokes
6280          * @param {Object}   scope    The scope of handler
6281          */
6282         removeResizeListener : function(fn, scope){
6283             if(resizeEvent){
6284                 resizeEvent.removeListener(fn, scope);
6285             }
6286         },
6287
6288         // private
6289         fireResize : function(){
6290             if(resizeEvent){
6291                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6292             }   
6293         },
6294         /**
6295          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6296          */
6297         ieDeferSrc : false,
6298         /**
6299          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6300          */
6301         textResizeInterval : 50
6302     };
6303     
6304     /**
6305      * Fix for doc tools
6306      * @scopeAlias pub=Roo.EventManager
6307      */
6308     
6309      /**
6310      * Appends an event handler to an element (shorthand for addListener)
6311      * @param {String/HTMLElement}   element        The html element or id to assign the
6312      * @param {String}   eventName The type of event to listen for
6313      * @param {Function} handler The method the event invokes
6314      * @param {Object}   scope (optional) The scope in which to execute the handler
6315      * function. The handler function's "this" context.
6316      * @param {Object}   options (optional) An object containing handler configuration
6317      * properties. This may contain any of the following properties:<ul>
6318      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6319      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6320      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6321      * <li>preventDefault {Boolean} True to prevent the default action</li>
6322      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6323      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6324      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6325      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6326      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6327      * by the specified number of milliseconds. If the event fires again within that time, the original
6328      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6329      * </ul><br>
6330      * <p>
6331      * <b>Combining Options</b><br>
6332      * Using the options argument, it is possible to combine different types of listeners:<br>
6333      * <br>
6334      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6335      * Code:<pre><code>
6336 el.on('click', this.onClick, this, {
6337     single: true,
6338     delay: 100,
6339     stopEvent : true,
6340     forumId: 4
6341 });</code></pre>
6342      * <p>
6343      * <b>Attaching multiple handlers in 1 call</b><br>
6344       * The method also allows for a single argument to be passed which is a config object containing properties
6345      * which specify multiple handlers.
6346      * <p>
6347      * Code:<pre><code>
6348 el.on({
6349     'click' : {
6350         fn: this.onClick
6351         scope: this,
6352         delay: 100
6353     },
6354     'mouseover' : {
6355         fn: this.onMouseOver
6356         scope: this
6357     },
6358     'mouseout' : {
6359         fn: this.onMouseOut
6360         scope: this
6361     }
6362 });</code></pre>
6363      * <p>
6364      * Or a shorthand syntax:<br>
6365      * Code:<pre><code>
6366 el.on({
6367     'click' : this.onClick,
6368     'mouseover' : this.onMouseOver,
6369     'mouseout' : this.onMouseOut
6370     scope: this
6371 });</code></pre>
6372      */
6373     pub.on = pub.addListener;
6374     pub.un = pub.removeListener;
6375
6376     pub.stoppedMouseDownEvent = new Roo.util.Event();
6377     return pub;
6378 }();
6379 /**
6380   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6381   * @param {Function} fn        The method the event invokes
6382   * @param {Object}   scope    An  object that becomes the scope of the handler
6383   * @param {boolean}  override If true, the obj passed in becomes
6384   *                             the execution scope of the listener
6385   * @member Roo
6386   * @method onReady
6387  */
6388 Roo.onReady = Roo.EventManager.onDocumentReady;
6389
6390 Roo.onReady(function(){
6391     var bd = Roo.get(document.body);
6392     if(!bd){ return; }
6393
6394     var cls = [
6395             Roo.isIE ? "roo-ie"
6396             : Roo.isGecko ? "roo-gecko"
6397             : Roo.isOpera ? "roo-opera"
6398             : Roo.isSafari ? "roo-safari" : ""];
6399
6400     if(Roo.isMac){
6401         cls.push("roo-mac");
6402     }
6403     if(Roo.isLinux){
6404         cls.push("roo-linux");
6405     }
6406     if(Roo.isBorderBox){
6407         cls.push('roo-border-box');
6408     }
6409     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6410         var p = bd.dom.parentNode;
6411         if(p){
6412             p.className += ' roo-strict';
6413         }
6414     }
6415     bd.addClass(cls.join(' '));
6416 });
6417
6418 /**
6419  * @class Roo.EventObject
6420  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6421  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6422  * Example:
6423  * <pre><code>
6424  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6425     e.preventDefault();
6426     var target = e.getTarget();
6427     ...
6428  }
6429  var myDiv = Roo.get("myDiv");
6430  myDiv.on("click", handleClick);
6431  //or
6432  Roo.EventManager.on("myDiv", 'click', handleClick);
6433  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6434  </code></pre>
6435  * @singleton
6436  */
6437 Roo.EventObject = function(){
6438     
6439     var E = Roo.lib.Event;
6440     
6441     // safari keypress events for special keys return bad keycodes
6442     var safariKeys = {
6443         63234 : 37, // left
6444         63235 : 39, // right
6445         63232 : 38, // up
6446         63233 : 40, // down
6447         63276 : 33, // page up
6448         63277 : 34, // page down
6449         63272 : 46, // delete
6450         63273 : 36, // home
6451         63275 : 35  // end
6452     };
6453
6454     // normalize button clicks
6455     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6456                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6457
6458     Roo.EventObjectImpl = function(e){
6459         if(e){
6460             this.setEvent(e.browserEvent || e);
6461         }
6462     };
6463     Roo.EventObjectImpl.prototype = {
6464         /**
6465          * Used to fix doc tools.
6466          * @scope Roo.EventObject.prototype
6467          */
6468             
6469
6470         
6471         
6472         /** The normal browser event */
6473         browserEvent : null,
6474         /** The button pressed in a mouse event */
6475         button : -1,
6476         /** True if the shift key was down during the event */
6477         shiftKey : false,
6478         /** True if the control key was down during the event */
6479         ctrlKey : false,
6480         /** True if the alt key was down during the event */
6481         altKey : false,
6482
6483         /** Key constant 
6484         * @type Number */
6485         BACKSPACE : 8,
6486         /** Key constant 
6487         * @type Number */
6488         TAB : 9,
6489         /** Key constant 
6490         * @type Number */
6491         RETURN : 13,
6492         /** Key constant 
6493         * @type Number */
6494         ENTER : 13,
6495         /** Key constant 
6496         * @type Number */
6497         SHIFT : 16,
6498         /** Key constant 
6499         * @type Number */
6500         CONTROL : 17,
6501         /** Key constant 
6502         * @type Number */
6503         ESC : 27,
6504         /** Key constant 
6505         * @type Number */
6506         SPACE : 32,
6507         /** Key constant 
6508         * @type Number */
6509         PAGEUP : 33,
6510         /** Key constant 
6511         * @type Number */
6512         PAGEDOWN : 34,
6513         /** Key constant 
6514         * @type Number */
6515         END : 35,
6516         /** Key constant 
6517         * @type Number */
6518         HOME : 36,
6519         /** Key constant 
6520         * @type Number */
6521         LEFT : 37,
6522         /** Key constant 
6523         * @type Number */
6524         UP : 38,
6525         /** Key constant 
6526         * @type Number */
6527         RIGHT : 39,
6528         /** Key constant 
6529         * @type Number */
6530         DOWN : 40,
6531         /** Key constant 
6532         * @type Number */
6533         DELETE : 46,
6534         /** Key constant 
6535         * @type Number */
6536         F5 : 116,
6537
6538            /** @private */
6539         setEvent : function(e){
6540             if(e == this || (e && e.browserEvent)){ // already wrapped
6541                 return e;
6542             }
6543             this.browserEvent = e;
6544             if(e){
6545                 // normalize buttons
6546                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6547                 if(e.type == 'click' && this.button == -1){
6548                     this.button = 0;
6549                 }
6550                 this.type = e.type;
6551                 this.shiftKey = e.shiftKey;
6552                 // mac metaKey behaves like ctrlKey
6553                 this.ctrlKey = e.ctrlKey || e.metaKey;
6554                 this.altKey = e.altKey;
6555                 // in getKey these will be normalized for the mac
6556                 this.keyCode = e.keyCode;
6557                 // keyup warnings on firefox.
6558                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6559                 // cache the target for the delayed and or buffered events
6560                 this.target = E.getTarget(e);
6561                 // same for XY
6562                 this.xy = E.getXY(e);
6563             }else{
6564                 this.button = -1;
6565                 this.shiftKey = false;
6566                 this.ctrlKey = false;
6567                 this.altKey = false;
6568                 this.keyCode = 0;
6569                 this.charCode =0;
6570                 this.target = null;
6571                 this.xy = [0, 0];
6572             }
6573             return this;
6574         },
6575
6576         /**
6577          * Stop the event (preventDefault and stopPropagation)
6578          */
6579         stopEvent : function(){
6580             if(this.browserEvent){
6581                 if(this.browserEvent.type == 'mousedown'){
6582                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6583                 }
6584                 E.stopEvent(this.browserEvent);
6585             }
6586         },
6587
6588         /**
6589          * Prevents the browsers default handling of the event.
6590          */
6591         preventDefault : function(){
6592             if(this.browserEvent){
6593                 E.preventDefault(this.browserEvent);
6594             }
6595         },
6596
6597         /** @private */
6598         isNavKeyPress : function(){
6599             var k = this.keyCode;
6600             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6601             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6602         },
6603
6604         isSpecialKey : function(){
6605             var k = this.keyCode;
6606             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6607             (k == 16) || (k == 17) ||
6608             (k >= 18 && k <= 20) ||
6609             (k >= 33 && k <= 35) ||
6610             (k >= 36 && k <= 39) ||
6611             (k >= 44 && k <= 45);
6612         },
6613         /**
6614          * Cancels bubbling of the event.
6615          */
6616         stopPropagation : function(){
6617             if(this.browserEvent){
6618                 if(this.type == 'mousedown'){
6619                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6620                 }
6621                 E.stopPropagation(this.browserEvent);
6622             }
6623         },
6624
6625         /**
6626          * Gets the key code for the event.
6627          * @return {Number}
6628          */
6629         getCharCode : function(){
6630             return this.charCode || this.keyCode;
6631         },
6632
6633         /**
6634          * Returns a normalized keyCode for the event.
6635          * @return {Number} The key code
6636          */
6637         getKey : function(){
6638             var k = this.keyCode || this.charCode;
6639             return Roo.isSafari ? (safariKeys[k] || k) : k;
6640         },
6641
6642         /**
6643          * Gets the x coordinate of the event.
6644          * @return {Number}
6645          */
6646         getPageX : function(){
6647             return this.xy[0];
6648         },
6649
6650         /**
6651          * Gets the y coordinate of the event.
6652          * @return {Number}
6653          */
6654         getPageY : function(){
6655             return this.xy[1];
6656         },
6657
6658         /**
6659          * Gets the time of the event.
6660          * @return {Number}
6661          */
6662         getTime : function(){
6663             if(this.browserEvent){
6664                 return E.getTime(this.browserEvent);
6665             }
6666             return null;
6667         },
6668
6669         /**
6670          * Gets the page coordinates of the event.
6671          * @return {Array} The xy values like [x, y]
6672          */
6673         getXY : function(){
6674             return this.xy;
6675         },
6676
6677         /**
6678          * Gets the target for the event.
6679          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6680          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6681                 search as a number or element (defaults to 10 || document.body)
6682          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6683          * @return {HTMLelement}
6684          */
6685         getTarget : function(selector, maxDepth, returnEl){
6686             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6687         },
6688         /**
6689          * Gets the related target.
6690          * @return {HTMLElement}
6691          */
6692         getRelatedTarget : function(){
6693             if(this.browserEvent){
6694                 return E.getRelatedTarget(this.browserEvent);
6695             }
6696             return null;
6697         },
6698
6699         /**
6700          * Normalizes mouse wheel delta across browsers
6701          * @return {Number} The delta
6702          */
6703         getWheelDelta : function(){
6704             var e = this.browserEvent;
6705             var delta = 0;
6706             if(e.wheelDelta){ /* IE/Opera. */
6707                 delta = e.wheelDelta/120;
6708             }else if(e.detail){ /* Mozilla case. */
6709                 delta = -e.detail/3;
6710             }
6711             return delta;
6712         },
6713
6714         /**
6715          * Returns true if the control, meta, shift or alt key was pressed during this event.
6716          * @return {Boolean}
6717          */
6718         hasModifier : function(){
6719             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6720         },
6721
6722         /**
6723          * Returns true if the target of this event equals el or is a child of el
6724          * @param {String/HTMLElement/Element} el
6725          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6726          * @return {Boolean}
6727          */
6728         within : function(el, related){
6729             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6730             return t && Roo.fly(el).contains(t);
6731         },
6732
6733         getPoint : function(){
6734             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6735         }
6736     };
6737
6738     return new Roo.EventObjectImpl();
6739 }();
6740             
6741     /*
6742  * Based on:
6743  * Ext JS Library 1.1.1
6744  * Copyright(c) 2006-2007, Ext JS, LLC.
6745  *
6746  * Originally Released Under LGPL - original licence link has changed is not relivant.
6747  *
6748  * Fork - LGPL
6749  * <script type="text/javascript">
6750  */
6751
6752  
6753 // was in Composite Element!??!?!
6754  
6755 (function(){
6756     var D = Roo.lib.Dom;
6757     var E = Roo.lib.Event;
6758     var A = Roo.lib.Anim;
6759
6760     // local style camelizing for speed
6761     var propCache = {};
6762     var camelRe = /(-[a-z])/gi;
6763     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6764     var view = document.defaultView;
6765
6766 /**
6767  * @class Roo.Element
6768  * Represents an Element in the DOM.<br><br>
6769  * Usage:<br>
6770 <pre><code>
6771 var el = Roo.get("my-div");
6772
6773 // or with getEl
6774 var el = getEl("my-div");
6775
6776 // or with a DOM element
6777 var el = Roo.get(myDivElement);
6778 </code></pre>
6779  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6780  * each call instead of constructing a new one.<br><br>
6781  * <b>Animations</b><br />
6782  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6783  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6784 <pre>
6785 Option    Default   Description
6786 --------- --------  ---------------------------------------------
6787 duration  .35       The duration of the animation in seconds
6788 easing    easeOut   The YUI easing method
6789 callback  none      A function to execute when the anim completes
6790 scope     this      The scope (this) of the callback function
6791 </pre>
6792 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6793 * manipulate the animation. Here's an example:
6794 <pre><code>
6795 var el = Roo.get("my-div");
6796
6797 // no animation
6798 el.setWidth(100);
6799
6800 // default animation
6801 el.setWidth(100, true);
6802
6803 // animation with some options set
6804 el.setWidth(100, {
6805     duration: 1,
6806     callback: this.foo,
6807     scope: this
6808 });
6809
6810 // using the "anim" property to get the Anim object
6811 var opt = {
6812     duration: 1,
6813     callback: this.foo,
6814     scope: this
6815 };
6816 el.setWidth(100, opt);
6817 ...
6818 if(opt.anim.isAnimated()){
6819     opt.anim.stop();
6820 }
6821 </code></pre>
6822 * <b> Composite (Collections of) Elements</b><br />
6823  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6824  * @constructor Create a new Element directly.
6825  * @param {String/HTMLElement} element
6826  * @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).
6827  */
6828     Roo.Element = function(element, forceNew){
6829         var dom = typeof element == "string" ?
6830                 document.getElementById(element) : element;
6831         if(!dom){ // invalid id/element
6832             return null;
6833         }
6834         var id = dom.id;
6835         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6836             return Roo.Element.cache[id];
6837         }
6838
6839         /**
6840          * The DOM element
6841          * @type HTMLElement
6842          */
6843         this.dom = dom;
6844
6845         /**
6846          * The DOM element ID
6847          * @type String
6848          */
6849         this.id = id || Roo.id(dom);
6850     };
6851
6852     var El = Roo.Element;
6853
6854     El.prototype = {
6855         /**
6856          * The element's default display mode  (defaults to "")
6857          * @type String
6858          */
6859         originalDisplay : "",
6860
6861         visibilityMode : 1,
6862         /**
6863          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6864          * @type String
6865          */
6866         defaultUnit : "px",
6867         /**
6868          * Sets the element's visibility mode. When setVisible() is called it
6869          * will use this to determine whether to set the visibility or the display property.
6870          * @param visMode Element.VISIBILITY or Element.DISPLAY
6871          * @return {Roo.Element} this
6872          */
6873         setVisibilityMode : function(visMode){
6874             this.visibilityMode = visMode;
6875             return this;
6876         },
6877         /**
6878          * Convenience method for setVisibilityMode(Element.DISPLAY)
6879          * @param {String} display (optional) What to set display to when visible
6880          * @return {Roo.Element} this
6881          */
6882         enableDisplayMode : function(display){
6883             this.setVisibilityMode(El.DISPLAY);
6884             if(typeof display != "undefined") this.originalDisplay = display;
6885             return this;
6886         },
6887
6888         /**
6889          * 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)
6890          * @param {String} selector The simple selector to test
6891          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6892                 search as a number or element (defaults to 10 || document.body)
6893          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6894          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6895          */
6896         findParent : function(simpleSelector, maxDepth, returnEl){
6897             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6898             maxDepth = maxDepth || 50;
6899             if(typeof maxDepth != "number"){
6900                 stopEl = Roo.getDom(maxDepth);
6901                 maxDepth = 10;
6902             }
6903             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6904                 if(dq.is(p, simpleSelector)){
6905                     return returnEl ? Roo.get(p) : p;
6906                 }
6907                 depth++;
6908                 p = p.parentNode;
6909             }
6910             return null;
6911         },
6912
6913
6914         /**
6915          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6916          * @param {String} selector The simple selector to test
6917          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6918                 search as a number or element (defaults to 10 || document.body)
6919          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6920          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6921          */
6922         findParentNode : function(simpleSelector, maxDepth, returnEl){
6923             var p = Roo.fly(this.dom.parentNode, '_internal');
6924             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6925         },
6926
6927         /**
6928          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6929          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6930          * @param {String} selector The simple selector to test
6931          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6932                 search as a number or element (defaults to 10 || document.body)
6933          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6934          */
6935         up : function(simpleSelector, maxDepth){
6936             return this.findParentNode(simpleSelector, maxDepth, true);
6937         },
6938
6939
6940
6941         /**
6942          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6943          * @param {String} selector The simple selector to test
6944          * @return {Boolean} True if this element matches the selector, else false
6945          */
6946         is : function(simpleSelector){
6947             return Roo.DomQuery.is(this.dom, simpleSelector);
6948         },
6949
6950         /**
6951          * Perform animation on this element.
6952          * @param {Object} args The YUI animation control args
6953          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6954          * @param {Function} onComplete (optional) Function to call when animation completes
6955          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6956          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6957          * @return {Roo.Element} this
6958          */
6959         animate : function(args, duration, onComplete, easing, animType){
6960             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6961             return this;
6962         },
6963
6964         /*
6965          * @private Internal animation call
6966          */
6967         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6968             animType = animType || 'run';
6969             opt = opt || {};
6970             var anim = Roo.lib.Anim[animType](
6971                 this.dom, args,
6972                 (opt.duration || defaultDur) || .35,
6973                 (opt.easing || defaultEase) || 'easeOut',
6974                 function(){
6975                     Roo.callback(cb, this);
6976                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6977                 },
6978                 this
6979             );
6980             opt.anim = anim;
6981             return anim;
6982         },
6983
6984         // private legacy anim prep
6985         preanim : function(a, i){
6986             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6987         },
6988
6989         /**
6990          * Removes worthless text nodes
6991          * @param {Boolean} forceReclean (optional) By default the element
6992          * keeps track if it has been cleaned already so
6993          * you can call this over and over. However, if you update the element and
6994          * need to force a reclean, you can pass true.
6995          */
6996         clean : function(forceReclean){
6997             if(this.isCleaned && forceReclean !== true){
6998                 return this;
6999             }
7000             var ns = /\S/;
7001             var d = this.dom, n = d.firstChild, ni = -1;
7002             while(n){
7003                 var nx = n.nextSibling;
7004                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7005                     d.removeChild(n);
7006                 }else{
7007                     n.nodeIndex = ++ni;
7008                 }
7009                 n = nx;
7010             }
7011             this.isCleaned = true;
7012             return this;
7013         },
7014
7015         // private
7016         calcOffsetsTo : function(el){
7017             el = Roo.get(el);
7018             var d = el.dom;
7019             var restorePos = false;
7020             if(el.getStyle('position') == 'static'){
7021                 el.position('relative');
7022                 restorePos = true;
7023             }
7024             var x = 0, y =0;
7025             var op = this.dom;
7026             while(op && op != d && op.tagName != 'HTML'){
7027                 x+= op.offsetLeft;
7028                 y+= op.offsetTop;
7029                 op = op.offsetParent;
7030             }
7031             if(restorePos){
7032                 el.position('static');
7033             }
7034             return [x, y];
7035         },
7036
7037         /**
7038          * Scrolls this element into view within the passed container.
7039          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7040          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7041          * @return {Roo.Element} this
7042          */
7043         scrollIntoView : function(container, hscroll){
7044             var c = Roo.getDom(container) || document.body;
7045             var el = this.dom;
7046
7047             var o = this.calcOffsetsTo(c),
7048                 l = o[0],
7049                 t = o[1],
7050                 b = t+el.offsetHeight,
7051                 r = l+el.offsetWidth;
7052
7053             var ch = c.clientHeight;
7054             var ct = parseInt(c.scrollTop, 10);
7055             var cl = parseInt(c.scrollLeft, 10);
7056             var cb = ct + ch;
7057             var cr = cl + c.clientWidth;
7058
7059             if(t < ct){
7060                 c.scrollTop = t;
7061             }else if(b > cb){
7062                 c.scrollTop = b-ch;
7063             }
7064
7065             if(hscroll !== false){
7066                 if(l < cl){
7067                     c.scrollLeft = l;
7068                 }else if(r > cr){
7069                     c.scrollLeft = r-c.clientWidth;
7070                 }
7071             }
7072             return this;
7073         },
7074
7075         // private
7076         scrollChildIntoView : function(child, hscroll){
7077             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7078         },
7079
7080         /**
7081          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7082          * the new height may not be available immediately.
7083          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7084          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7085          * @param {Function} onComplete (optional) Function to call when animation completes
7086          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7087          * @return {Roo.Element} this
7088          */
7089         autoHeight : function(animate, duration, onComplete, easing){
7090             var oldHeight = this.getHeight();
7091             this.clip();
7092             this.setHeight(1); // force clipping
7093             setTimeout(function(){
7094                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7095                 if(!animate){
7096                     this.setHeight(height);
7097                     this.unclip();
7098                     if(typeof onComplete == "function"){
7099                         onComplete();
7100                     }
7101                 }else{
7102                     this.setHeight(oldHeight); // restore original height
7103                     this.setHeight(height, animate, duration, function(){
7104                         this.unclip();
7105                         if(typeof onComplete == "function") onComplete();
7106                     }.createDelegate(this), easing);
7107                 }
7108             }.createDelegate(this), 0);
7109             return this;
7110         },
7111
7112         /**
7113          * Returns true if this element is an ancestor of the passed element
7114          * @param {HTMLElement/String} el The element to check
7115          * @return {Boolean} True if this element is an ancestor of el, else false
7116          */
7117         contains : function(el){
7118             if(!el){return false;}
7119             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7120         },
7121
7122         /**
7123          * Checks whether the element is currently visible using both visibility and display properties.
7124          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7125          * @return {Boolean} True if the element is currently visible, else false
7126          */
7127         isVisible : function(deep) {
7128             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7129             if(deep !== true || !vis){
7130                 return vis;
7131             }
7132             var p = this.dom.parentNode;
7133             while(p && p.tagName.toLowerCase() != "body"){
7134                 if(!Roo.fly(p, '_isVisible').isVisible()){
7135                     return false;
7136                 }
7137                 p = p.parentNode;
7138             }
7139             return true;
7140         },
7141
7142         /**
7143          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7144          * @param {String} selector The CSS selector
7145          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7146          * @return {CompositeElement/CompositeElementLite} The composite element
7147          */
7148         select : function(selector, unique){
7149             return El.select(selector, unique, this.dom);
7150         },
7151
7152         /**
7153          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7154          * @param {String} selector The CSS selector
7155          * @return {Array} An array of the matched nodes
7156          */
7157         query : function(selector, unique){
7158             return Roo.DomQuery.select(selector, this.dom);
7159         },
7160
7161         /**
7162          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7163          * @param {String} selector The CSS selector
7164          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7165          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7166          */
7167         child : function(selector, returnDom){
7168             var n = Roo.DomQuery.selectNode(selector, this.dom);
7169             return returnDom ? n : Roo.get(n);
7170         },
7171
7172         /**
7173          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7174          * @param {String} selector The CSS selector
7175          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7176          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7177          */
7178         down : function(selector, returnDom){
7179             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7180             return returnDom ? n : Roo.get(n);
7181         },
7182
7183         /**
7184          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7185          * @param {String} group The group the DD object is member of
7186          * @param {Object} config The DD config object
7187          * @param {Object} overrides An object containing methods to override/implement on the DD object
7188          * @return {Roo.dd.DD} The DD object
7189          */
7190         initDD : function(group, config, overrides){
7191             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7192             return Roo.apply(dd, overrides);
7193         },
7194
7195         /**
7196          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7197          * @param {String} group The group the DDProxy object is member of
7198          * @param {Object} config The DDProxy config object
7199          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7200          * @return {Roo.dd.DDProxy} The DDProxy object
7201          */
7202         initDDProxy : function(group, config, overrides){
7203             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7204             return Roo.apply(dd, overrides);
7205         },
7206
7207         /**
7208          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7209          * @param {String} group The group the DDTarget object is member of
7210          * @param {Object} config The DDTarget config object
7211          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7212          * @return {Roo.dd.DDTarget} The DDTarget object
7213          */
7214         initDDTarget : function(group, config, overrides){
7215             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7216             return Roo.apply(dd, overrides);
7217         },
7218
7219         /**
7220          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7221          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7222          * @param {Boolean} visible Whether the element is visible
7223          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7224          * @return {Roo.Element} this
7225          */
7226          setVisible : function(visible, animate){
7227             if(!animate || !A){
7228                 if(this.visibilityMode == El.DISPLAY){
7229                     this.setDisplayed(visible);
7230                 }else{
7231                     this.fixDisplay();
7232                     this.dom.style.visibility = visible ? "visible" : "hidden";
7233                 }
7234             }else{
7235                 // closure for composites
7236                 var dom = this.dom;
7237                 var visMode = this.visibilityMode;
7238                 if(visible){
7239                     this.setOpacity(.01);
7240                     this.setVisible(true);
7241                 }
7242                 this.anim({opacity: { to: (visible?1:0) }},
7243                       this.preanim(arguments, 1),
7244                       null, .35, 'easeIn', function(){
7245                          if(!visible){
7246                              if(visMode == El.DISPLAY){
7247                                  dom.style.display = "none";
7248                              }else{
7249                                  dom.style.visibility = "hidden";
7250                              }
7251                              Roo.get(dom).setOpacity(1);
7252                          }
7253                      });
7254             }
7255             return this;
7256         },
7257
7258         /**
7259          * Returns true if display is not "none"
7260          * @return {Boolean}
7261          */
7262         isDisplayed : function() {
7263             return this.getStyle("display") != "none";
7264         },
7265
7266         /**
7267          * Toggles the element's visibility or display, depending on visibility mode.
7268          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7269          * @return {Roo.Element} this
7270          */
7271         toggle : function(animate){
7272             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7273             return this;
7274         },
7275
7276         /**
7277          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7278          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7279          * @return {Roo.Element} this
7280          */
7281         setDisplayed : function(value) {
7282             if(typeof value == "boolean"){
7283                value = value ? this.originalDisplay : "none";
7284             }
7285             this.setStyle("display", value);
7286             return this;
7287         },
7288
7289         /**
7290          * Tries to focus the element. Any exceptions are caught and ignored.
7291          * @return {Roo.Element} this
7292          */
7293         focus : function() {
7294             try{
7295                 this.dom.focus();
7296             }catch(e){}
7297             return this;
7298         },
7299
7300         /**
7301          * Tries to blur the element. Any exceptions are caught and ignored.
7302          * @return {Roo.Element} this
7303          */
7304         blur : function() {
7305             try{
7306                 this.dom.blur();
7307             }catch(e){}
7308             return this;
7309         },
7310
7311         /**
7312          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7313          * @param {String/Array} className The CSS class to add, or an array of classes
7314          * @return {Roo.Element} this
7315          */
7316         addClass : function(className){
7317             if(className instanceof Array){
7318                 for(var i = 0, len = className.length; i < len; i++) {
7319                     this.addClass(className[i]);
7320                 }
7321             }else{
7322                 if(className && !this.hasClass(className)){
7323                     this.dom.className = this.dom.className + " " + className;
7324                 }
7325             }
7326             return this;
7327         },
7328
7329         /**
7330          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7331          * @param {String/Array} className The CSS class to add, or an array of classes
7332          * @return {Roo.Element} this
7333          */
7334         radioClass : function(className){
7335             var siblings = this.dom.parentNode.childNodes;
7336             for(var i = 0; i < siblings.length; i++) {
7337                 var s = siblings[i];
7338                 if(s.nodeType == 1){
7339                     Roo.get(s).removeClass(className);
7340                 }
7341             }
7342             this.addClass(className);
7343             return this;
7344         },
7345
7346         /**
7347          * Removes one or more CSS classes from the element.
7348          * @param {String/Array} className The CSS class to remove, or an array of classes
7349          * @return {Roo.Element} this
7350          */
7351         removeClass : function(className){
7352             if(!className || !this.dom.className){
7353                 return this;
7354             }
7355             if(className instanceof Array){
7356                 for(var i = 0, len = className.length; i < len; i++) {
7357                     this.removeClass(className[i]);
7358                 }
7359             }else{
7360                 if(this.hasClass(className)){
7361                     var re = this.classReCache[className];
7362                     if (!re) {
7363                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7364                        this.classReCache[className] = re;
7365                     }
7366                     this.dom.className =
7367                         this.dom.className.replace(re, " ");
7368                 }
7369             }
7370             return this;
7371         },
7372
7373         // private
7374         classReCache: {},
7375
7376         /**
7377          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7378          * @param {String} className The CSS class to toggle
7379          * @return {Roo.Element} this
7380          */
7381         toggleClass : function(className){
7382             if(this.hasClass(className)){
7383                 this.removeClass(className);
7384             }else{
7385                 this.addClass(className);
7386             }
7387             return this;
7388         },
7389
7390         /**
7391          * Checks if the specified CSS class exists on this element's DOM node.
7392          * @param {String} className The CSS class to check for
7393          * @return {Boolean} True if the class exists, else false
7394          */
7395         hasClass : function(className){
7396             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7397         },
7398
7399         /**
7400          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7401          * @param {String} oldClassName The CSS class to replace
7402          * @param {String} newClassName The replacement CSS class
7403          * @return {Roo.Element} this
7404          */
7405         replaceClass : function(oldClassName, newClassName){
7406             this.removeClass(oldClassName);
7407             this.addClass(newClassName);
7408             return this;
7409         },
7410
7411         /**
7412          * Returns an object with properties matching the styles requested.
7413          * For example, el.getStyles('color', 'font-size', 'width') might return
7414          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7415          * @param {String} style1 A style name
7416          * @param {String} style2 A style name
7417          * @param {String} etc.
7418          * @return {Object} The style object
7419          */
7420         getStyles : function(){
7421             var a = arguments, len = a.length, r = {};
7422             for(var i = 0; i < len; i++){
7423                 r[a[i]] = this.getStyle(a[i]);
7424             }
7425             return r;
7426         },
7427
7428         /**
7429          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7430          * @param {String} property The style property whose value is returned.
7431          * @return {String} The current value of the style property for this element.
7432          */
7433         getStyle : function(){
7434             return view && view.getComputedStyle ?
7435                 function(prop){
7436                     var el = this.dom, v, cs, camel;
7437                     if(prop == 'float'){
7438                         prop = "cssFloat";
7439                     }
7440                     if(el.style && (v = el.style[prop])){
7441                         return v;
7442                     }
7443                     if(cs = view.getComputedStyle(el, "")){
7444                         if(!(camel = propCache[prop])){
7445                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7446                         }
7447                         return cs[camel];
7448                     }
7449                     return null;
7450                 } :
7451                 function(prop){
7452                     var el = this.dom, v, cs, camel;
7453                     if(prop == 'opacity'){
7454                         if(typeof el.style.filter == 'string'){
7455                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7456                             if(m){
7457                                 var fv = parseFloat(m[1]);
7458                                 if(!isNaN(fv)){
7459                                     return fv ? fv / 100 : 0;
7460                                 }
7461                             }
7462                         }
7463                         return 1;
7464                     }else if(prop == 'float'){
7465                         prop = "styleFloat";
7466                     }
7467                     if(!(camel = propCache[prop])){
7468                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7469                     }
7470                     if(v = el.style[camel]){
7471                         return v;
7472                     }
7473                     if(cs = el.currentStyle){
7474                         return cs[camel];
7475                     }
7476                     return null;
7477                 };
7478         }(),
7479
7480         /**
7481          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7482          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7483          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7484          * @return {Roo.Element} this
7485          */
7486         setStyle : function(prop, value){
7487             if(typeof prop == "string"){
7488                 
7489                 if (prop == 'float') {
7490                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7491                     return this;
7492                 }
7493                 
7494                 var camel;
7495                 if(!(camel = propCache[prop])){
7496                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7497                 }
7498                 
7499                 if(camel == 'opacity') {
7500                     this.setOpacity(value);
7501                 }else{
7502                     this.dom.style[camel] = value;
7503                 }
7504             }else{
7505                 for(var style in prop){
7506                     if(typeof prop[style] != "function"){
7507                        this.setStyle(style, prop[style]);
7508                     }
7509                 }
7510             }
7511             return this;
7512         },
7513
7514         /**
7515          * More flexible version of {@link #setStyle} for setting style properties.
7516          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7517          * a function which returns such a specification.
7518          * @return {Roo.Element} this
7519          */
7520         applyStyles : function(style){
7521             Roo.DomHelper.applyStyles(this.dom, style);
7522             return this;
7523         },
7524
7525         /**
7526           * 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).
7527           * @return {Number} The X position of the element
7528           */
7529         getX : function(){
7530             return D.getX(this.dom);
7531         },
7532
7533         /**
7534           * 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).
7535           * @return {Number} The Y position of the element
7536           */
7537         getY : function(){
7538             return D.getY(this.dom);
7539         },
7540
7541         /**
7542           * 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).
7543           * @return {Array} The XY position of the element
7544           */
7545         getXY : function(){
7546             return D.getXY(this.dom);
7547         },
7548
7549         /**
7550          * 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).
7551          * @param {Number} The X position of the element
7552          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7553          * @return {Roo.Element} this
7554          */
7555         setX : function(x, animate){
7556             if(!animate || !A){
7557                 D.setX(this.dom, x);
7558             }else{
7559                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7560             }
7561             return this;
7562         },
7563
7564         /**
7565          * 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).
7566          * @param {Number} The Y position of the element
7567          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7568          * @return {Roo.Element} this
7569          */
7570         setY : function(y, animate){
7571             if(!animate || !A){
7572                 D.setY(this.dom, y);
7573             }else{
7574                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7575             }
7576             return this;
7577         },
7578
7579         /**
7580          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7581          * @param {String} left The left CSS property value
7582          * @return {Roo.Element} this
7583          */
7584         setLeft : function(left){
7585             this.setStyle("left", this.addUnits(left));
7586             return this;
7587         },
7588
7589         /**
7590          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7591          * @param {String} top The top CSS property value
7592          * @return {Roo.Element} this
7593          */
7594         setTop : function(top){
7595             this.setStyle("top", this.addUnits(top));
7596             return this;
7597         },
7598
7599         /**
7600          * Sets the element's CSS right style.
7601          * @param {String} right The right CSS property value
7602          * @return {Roo.Element} this
7603          */
7604         setRight : function(right){
7605             this.setStyle("right", this.addUnits(right));
7606             return this;
7607         },
7608
7609         /**
7610          * Sets the element's CSS bottom style.
7611          * @param {String} bottom The bottom CSS property value
7612          * @return {Roo.Element} this
7613          */
7614         setBottom : function(bottom){
7615             this.setStyle("bottom", this.addUnits(bottom));
7616             return this;
7617         },
7618
7619         /**
7620          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7621          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7622          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7623          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7624          * @return {Roo.Element} this
7625          */
7626         setXY : function(pos, animate){
7627             if(!animate || !A){
7628                 D.setXY(this.dom, pos);
7629             }else{
7630                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7631             }
7632             return this;
7633         },
7634
7635         /**
7636          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7637          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7638          * @param {Number} x X value for new position (coordinates are page-based)
7639          * @param {Number} y Y value for new position (coordinates are page-based)
7640          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7641          * @return {Roo.Element} this
7642          */
7643         setLocation : function(x, y, animate){
7644             this.setXY([x, y], this.preanim(arguments, 2));
7645             return this;
7646         },
7647
7648         /**
7649          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7650          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7651          * @param {Number} x X value for new position (coordinates are page-based)
7652          * @param {Number} y Y value for new position (coordinates are page-based)
7653          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7654          * @return {Roo.Element} this
7655          */
7656         moveTo : function(x, y, animate){
7657             this.setXY([x, y], this.preanim(arguments, 2));
7658             return this;
7659         },
7660
7661         /**
7662          * Returns the region of the given element.
7663          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7664          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7665          */
7666         getRegion : function(){
7667             return D.getRegion(this.dom);
7668         },
7669
7670         /**
7671          * Returns the offset height of the element
7672          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7673          * @return {Number} The element's height
7674          */
7675         getHeight : function(contentHeight){
7676             var h = this.dom.offsetHeight || 0;
7677             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7678         },
7679
7680         /**
7681          * Returns the offset width of the element
7682          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7683          * @return {Number} The element's width
7684          */
7685         getWidth : function(contentWidth){
7686             var w = this.dom.offsetWidth || 0;
7687             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7688         },
7689
7690         /**
7691          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7692          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7693          * if a height has not been set using CSS.
7694          * @return {Number}
7695          */
7696         getComputedHeight : function(){
7697             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7698             if(!h){
7699                 h = parseInt(this.getStyle('height'), 10) || 0;
7700                 if(!this.isBorderBox()){
7701                     h += this.getFrameWidth('tb');
7702                 }
7703             }
7704             return h;
7705         },
7706
7707         /**
7708          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7709          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7710          * if a width has not been set using CSS.
7711          * @return {Number}
7712          */
7713         getComputedWidth : function(){
7714             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7715             if(!w){
7716                 w = parseInt(this.getStyle('width'), 10) || 0;
7717                 if(!this.isBorderBox()){
7718                     w += this.getFrameWidth('lr');
7719                 }
7720             }
7721             return w;
7722         },
7723
7724         /**
7725          * Returns the size of the element.
7726          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7727          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7728          */
7729         getSize : function(contentSize){
7730             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7731         },
7732
7733         /**
7734          * Returns the width and height of the viewport.
7735          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7736          */
7737         getViewSize : function(){
7738             var d = this.dom, doc = document, aw = 0, ah = 0;
7739             if(d == doc || d == doc.body){
7740                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7741             }else{
7742                 return {
7743                     width : d.clientWidth,
7744                     height: d.clientHeight
7745                 };
7746             }
7747         },
7748
7749         /**
7750          * Returns the value of the "value" attribute
7751          * @param {Boolean} asNumber true to parse the value as a number
7752          * @return {String/Number}
7753          */
7754         getValue : function(asNumber){
7755             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7756         },
7757
7758         // private
7759         adjustWidth : function(width){
7760             if(typeof width == "number"){
7761                 if(this.autoBoxAdjust && !this.isBorderBox()){
7762                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7763                 }
7764                 if(width < 0){
7765                     width = 0;
7766                 }
7767             }
7768             return width;
7769         },
7770
7771         // private
7772         adjustHeight : function(height){
7773             if(typeof height == "number"){
7774                if(this.autoBoxAdjust && !this.isBorderBox()){
7775                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7776                }
7777                if(height < 0){
7778                    height = 0;
7779                }
7780             }
7781             return height;
7782         },
7783
7784         /**
7785          * Set the width of the element
7786          * @param {Number} width The new width
7787          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7788          * @return {Roo.Element} this
7789          */
7790         setWidth : function(width, animate){
7791             width = this.adjustWidth(width);
7792             if(!animate || !A){
7793                 this.dom.style.width = this.addUnits(width);
7794             }else{
7795                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7796             }
7797             return this;
7798         },
7799
7800         /**
7801          * Set the height of the element
7802          * @param {Number} height The new height
7803          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7804          * @return {Roo.Element} this
7805          */
7806          setHeight : function(height, animate){
7807             height = this.adjustHeight(height);
7808             if(!animate || !A){
7809                 this.dom.style.height = this.addUnits(height);
7810             }else{
7811                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7812             }
7813             return this;
7814         },
7815
7816         /**
7817          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7818          * @param {Number} width The new width
7819          * @param {Number} height The new height
7820          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7821          * @return {Roo.Element} this
7822          */
7823          setSize : function(width, height, animate){
7824             if(typeof width == "object"){ // in case of object from getSize()
7825                 height = width.height; width = width.width;
7826             }
7827             width = this.adjustWidth(width); height = this.adjustHeight(height);
7828             if(!animate || !A){
7829                 this.dom.style.width = this.addUnits(width);
7830                 this.dom.style.height = this.addUnits(height);
7831             }else{
7832                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7833             }
7834             return this;
7835         },
7836
7837         /**
7838          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7839          * @param {Number} x X value for new position (coordinates are page-based)
7840          * @param {Number} y Y value for new position (coordinates are page-based)
7841          * @param {Number} width The new width
7842          * @param {Number} height The new height
7843          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7844          * @return {Roo.Element} this
7845          */
7846         setBounds : function(x, y, width, height, animate){
7847             if(!animate || !A){
7848                 this.setSize(width, height);
7849                 this.setLocation(x, y);
7850             }else{
7851                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7852                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7853                               this.preanim(arguments, 4), 'motion');
7854             }
7855             return this;
7856         },
7857
7858         /**
7859          * 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.
7860          * @param {Roo.lib.Region} region The region to fill
7861          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7862          * @return {Roo.Element} this
7863          */
7864         setRegion : function(region, animate){
7865             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7866             return this;
7867         },
7868
7869         /**
7870          * Appends an event handler
7871          *
7872          * @param {String}   eventName     The type of event to append
7873          * @param {Function} fn        The method the event invokes
7874          * @param {Object} scope       (optional) The scope (this object) of the fn
7875          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7876          */
7877         addListener : function(eventName, fn, scope, options){
7878             if (this.dom) {
7879                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7880             }
7881         },
7882
7883         /**
7884          * Removes an event handler from this element
7885          * @param {String} eventName the type of event to remove
7886          * @param {Function} fn the method the event invokes
7887          * @return {Roo.Element} this
7888          */
7889         removeListener : function(eventName, fn){
7890             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7891             return this;
7892         },
7893
7894         /**
7895          * Removes all previous added listeners from this element
7896          * @return {Roo.Element} this
7897          */
7898         removeAllListeners : function(){
7899             E.purgeElement(this.dom);
7900             return this;
7901         },
7902
7903         relayEvent : function(eventName, observable){
7904             this.on(eventName, function(e){
7905                 observable.fireEvent(eventName, e);
7906             });
7907         },
7908
7909         /**
7910          * Set the opacity of the element
7911          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
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          setOpacity : function(opacity, animate){
7916             if(!animate || !A){
7917                 var s = this.dom.style;
7918                 if(Roo.isIE){
7919                     s.zoom = 1;
7920                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7921                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7922                 }else{
7923                     s.opacity = opacity;
7924                 }
7925             }else{
7926                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7927             }
7928             return this;
7929         },
7930
7931         /**
7932          * Gets the left X coordinate
7933          * @param {Boolean} local True to get the local css position instead of page coordinate
7934          * @return {Number}
7935          */
7936         getLeft : function(local){
7937             if(!local){
7938                 return this.getX();
7939             }else{
7940                 return parseInt(this.getStyle("left"), 10) || 0;
7941             }
7942         },
7943
7944         /**
7945          * Gets the right X coordinate of the element (element X position + element width)
7946          * @param {Boolean} local True to get the local css position instead of page coordinate
7947          * @return {Number}
7948          */
7949         getRight : function(local){
7950             if(!local){
7951                 return this.getX() + this.getWidth();
7952             }else{
7953                 return (this.getLeft(true) + this.getWidth()) || 0;
7954             }
7955         },
7956
7957         /**
7958          * Gets the top Y coordinate
7959          * @param {Boolean} local True to get the local css position instead of page coordinate
7960          * @return {Number}
7961          */
7962         getTop : function(local) {
7963             if(!local){
7964                 return this.getY();
7965             }else{
7966                 return parseInt(this.getStyle("top"), 10) || 0;
7967             }
7968         },
7969
7970         /**
7971          * Gets the bottom Y coordinate of the element (element Y position + element height)
7972          * @param {Boolean} local True to get the local css position instead of page coordinate
7973          * @return {Number}
7974          */
7975         getBottom : function(local){
7976             if(!local){
7977                 return this.getY() + this.getHeight();
7978             }else{
7979                 return (this.getTop(true) + this.getHeight()) || 0;
7980             }
7981         },
7982
7983         /**
7984         * Initializes positioning on this element. If a desired position is not passed, it will make the
7985         * the element positioned relative IF it is not already positioned.
7986         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7987         * @param {Number} zIndex (optional) The zIndex to apply
7988         * @param {Number} x (optional) Set the page X position
7989         * @param {Number} y (optional) Set the page Y position
7990         */
7991         position : function(pos, zIndex, x, y){
7992             if(!pos){
7993                if(this.getStyle('position') == 'static'){
7994                    this.setStyle('position', 'relative');
7995                }
7996             }else{
7997                 this.setStyle("position", pos);
7998             }
7999             if(zIndex){
8000                 this.setStyle("z-index", zIndex);
8001             }
8002             if(x !== undefined && y !== undefined){
8003                 this.setXY([x, y]);
8004             }else if(x !== undefined){
8005                 this.setX(x);
8006             }else if(y !== undefined){
8007                 this.setY(y);
8008             }
8009         },
8010
8011         /**
8012         * Clear positioning back to the default when the document was loaded
8013         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8014         * @return {Roo.Element} this
8015          */
8016         clearPositioning : function(value){
8017             value = value ||'';
8018             this.setStyle({
8019                 "left": value,
8020                 "right": value,
8021                 "top": value,
8022                 "bottom": value,
8023                 "z-index": "",
8024                 "position" : "static"
8025             });
8026             return this;
8027         },
8028
8029         /**
8030         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8031         * snapshot before performing an update and then restoring the element.
8032         * @return {Object}
8033         */
8034         getPositioning : function(){
8035             var l = this.getStyle("left");
8036             var t = this.getStyle("top");
8037             return {
8038                 "position" : this.getStyle("position"),
8039                 "left" : l,
8040                 "right" : l ? "" : this.getStyle("right"),
8041                 "top" : t,
8042                 "bottom" : t ? "" : this.getStyle("bottom"),
8043                 "z-index" : this.getStyle("z-index")
8044             };
8045         },
8046
8047         /**
8048          * Gets the width of the border(s) for the specified side(s)
8049          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8050          * passing lr would get the border (l)eft width + the border (r)ight width.
8051          * @return {Number} The width of the sides passed added together
8052          */
8053         getBorderWidth : function(side){
8054             return this.addStyles(side, El.borders);
8055         },
8056
8057         /**
8058          * Gets the width of the padding(s) for the specified side(s)
8059          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8060          * passing lr would get the padding (l)eft + the padding (r)ight.
8061          * @return {Number} The padding of the sides passed added together
8062          */
8063         getPadding : function(side){
8064             return this.addStyles(side, El.paddings);
8065         },
8066
8067         /**
8068         * Set positioning with an object returned by getPositioning().
8069         * @param {Object} posCfg
8070         * @return {Roo.Element} this
8071          */
8072         setPositioning : function(pc){
8073             this.applyStyles(pc);
8074             if(pc.right == "auto"){
8075                 this.dom.style.right = "";
8076             }
8077             if(pc.bottom == "auto"){
8078                 this.dom.style.bottom = "";
8079             }
8080             return this;
8081         },
8082
8083         // private
8084         fixDisplay : function(){
8085             if(this.getStyle("display") == "none"){
8086                 this.setStyle("visibility", "hidden");
8087                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8088                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8089                     this.setStyle("display", "block");
8090                 }
8091             }
8092         },
8093
8094         /**
8095          * Quick set left and top adding default units
8096          * @param {String} left The left CSS property value
8097          * @param {String} top The top CSS property value
8098          * @return {Roo.Element} this
8099          */
8100          setLeftTop : function(left, top){
8101             this.dom.style.left = this.addUnits(left);
8102             this.dom.style.top = this.addUnits(top);
8103             return this;
8104         },
8105
8106         /**
8107          * Move this element relative to its current position.
8108          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8109          * @param {Number} distance How far to move the element in pixels
8110          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8111          * @return {Roo.Element} this
8112          */
8113          move : function(direction, distance, animate){
8114             var xy = this.getXY();
8115             direction = direction.toLowerCase();
8116             switch(direction){
8117                 case "l":
8118                 case "left":
8119                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8120                     break;
8121                case "r":
8122                case "right":
8123                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8124                     break;
8125                case "t":
8126                case "top":
8127                case "up":
8128                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8129                     break;
8130                case "b":
8131                case "bottom":
8132                case "down":
8133                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8134                     break;
8135             }
8136             return this;
8137         },
8138
8139         /**
8140          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8141          * @return {Roo.Element} this
8142          */
8143         clip : function(){
8144             if(!this.isClipped){
8145                this.isClipped = true;
8146                this.originalClip = {
8147                    "o": this.getStyle("overflow"),
8148                    "x": this.getStyle("overflow-x"),
8149                    "y": this.getStyle("overflow-y")
8150                };
8151                this.setStyle("overflow", "hidden");
8152                this.setStyle("overflow-x", "hidden");
8153                this.setStyle("overflow-y", "hidden");
8154             }
8155             return this;
8156         },
8157
8158         /**
8159          *  Return clipping (overflow) to original clipping before clip() was called
8160          * @return {Roo.Element} this
8161          */
8162         unclip : function(){
8163             if(this.isClipped){
8164                 this.isClipped = false;
8165                 var o = this.originalClip;
8166                 if(o.o){this.setStyle("overflow", o.o);}
8167                 if(o.x){this.setStyle("overflow-x", o.x);}
8168                 if(o.y){this.setStyle("overflow-y", o.y);}
8169             }
8170             return this;
8171         },
8172
8173
8174         /**
8175          * Gets the x,y coordinates specified by the anchor position on the element.
8176          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8177          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8178          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8179          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8180          * @return {Array} [x, y] An array containing the element's x and y coordinates
8181          */
8182         getAnchorXY : function(anchor, local, s){
8183             //Passing a different size is useful for pre-calculating anchors,
8184             //especially for anchored animations that change the el size.
8185
8186             var w, h, vp = false;
8187             if(!s){
8188                 var d = this.dom;
8189                 if(d == document.body || d == document){
8190                     vp = true;
8191                     w = D.getViewWidth(); h = D.getViewHeight();
8192                 }else{
8193                     w = this.getWidth(); h = this.getHeight();
8194                 }
8195             }else{
8196                 w = s.width;  h = s.height;
8197             }
8198             var x = 0, y = 0, r = Math.round;
8199             switch((anchor || "tl").toLowerCase()){
8200                 case "c":
8201                     x = r(w*.5);
8202                     y = r(h*.5);
8203                 break;
8204                 case "t":
8205                     x = r(w*.5);
8206                     y = 0;
8207                 break;
8208                 case "l":
8209                     x = 0;
8210                     y = r(h*.5);
8211                 break;
8212                 case "r":
8213                     x = w;
8214                     y = r(h*.5);
8215                 break;
8216                 case "b":
8217                     x = r(w*.5);
8218                     y = h;
8219                 break;
8220                 case "tl":
8221                     x = 0;
8222                     y = 0;
8223                 break;
8224                 case "bl":
8225                     x = 0;
8226                     y = h;
8227                 break;
8228                 case "br":
8229                     x = w;
8230                     y = h;
8231                 break;
8232                 case "tr":
8233                     x = w;
8234                     y = 0;
8235                 break;
8236             }
8237             if(local === true){
8238                 return [x, y];
8239             }
8240             if(vp){
8241                 var sc = this.getScroll();
8242                 return [x + sc.left, y + sc.top];
8243             }
8244             //Add the element's offset xy
8245             var o = this.getXY();
8246             return [x+o[0], y+o[1]];
8247         },
8248
8249         /**
8250          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8251          * supported position values.
8252          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8253          * @param {String} position The position to align to.
8254          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8255          * @return {Array} [x, y]
8256          */
8257         getAlignToXY : function(el, p, o){
8258             el = Roo.get(el);
8259             var d = this.dom;
8260             if(!el.dom){
8261                 throw "Element.alignTo with an element that doesn't exist";
8262             }
8263             var c = false; //constrain to viewport
8264             var p1 = "", p2 = "";
8265             o = o || [0,0];
8266
8267             if(!p){
8268                 p = "tl-bl";
8269             }else if(p == "?"){
8270                 p = "tl-bl?";
8271             }else if(p.indexOf("-") == -1){
8272                 p = "tl-" + p;
8273             }
8274             p = p.toLowerCase();
8275             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8276             if(!m){
8277                throw "Element.alignTo with an invalid alignment " + p;
8278             }
8279             p1 = m[1]; p2 = m[2]; c = !!m[3];
8280
8281             //Subtract the aligned el's internal xy from the target's offset xy
8282             //plus custom offset to get the aligned el's new offset xy
8283             var a1 = this.getAnchorXY(p1, true);
8284             var a2 = el.getAnchorXY(p2, false);
8285             var x = a2[0] - a1[0] + o[0];
8286             var y = a2[1] - a1[1] + o[1];
8287             if(c){
8288                 //constrain the aligned el to viewport if necessary
8289                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8290                 // 5px of margin for ie
8291                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8292
8293                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8294                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8295                 //otherwise swap the aligned el to the opposite border of the target.
8296                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8297                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8298                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8299                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8300
8301                var doc = document;
8302                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8303                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8304
8305                if((x+w) > dw + scrollX){
8306                     x = swapX ? r.left-w : dw+scrollX-w;
8307                 }
8308                if(x < scrollX){
8309                    x = swapX ? r.right : scrollX;
8310                }
8311                if((y+h) > dh + scrollY){
8312                     y = swapY ? r.top-h : dh+scrollY-h;
8313                 }
8314                if (y < scrollY){
8315                    y = swapY ? r.bottom : scrollY;
8316                }
8317             }
8318             return [x,y];
8319         },
8320
8321         // private
8322         getConstrainToXY : function(){
8323             var os = {top:0, left:0, bottom:0, right: 0};
8324
8325             return function(el, local, offsets, proposedXY){
8326                 el = Roo.get(el);
8327                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8328
8329                 var vw, vh, vx = 0, vy = 0;
8330                 if(el.dom == document.body || el.dom == document){
8331                     vw = Roo.lib.Dom.getViewWidth();
8332                     vh = Roo.lib.Dom.getViewHeight();
8333                 }else{
8334                     vw = el.dom.clientWidth;
8335                     vh = el.dom.clientHeight;
8336                     if(!local){
8337                         var vxy = el.getXY();
8338                         vx = vxy[0];
8339                         vy = vxy[1];
8340                     }
8341                 }
8342
8343                 var s = el.getScroll();
8344
8345                 vx += offsets.left + s.left;
8346                 vy += offsets.top + s.top;
8347
8348                 vw -= offsets.right;
8349                 vh -= offsets.bottom;
8350
8351                 var vr = vx+vw;
8352                 var vb = vy+vh;
8353
8354                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8355                 var x = xy[0], y = xy[1];
8356                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8357
8358                 // only move it if it needs it
8359                 var moved = false;
8360
8361                 // first validate right/bottom
8362                 if((x + w) > vr){
8363                     x = vr - w;
8364                     moved = true;
8365                 }
8366                 if((y + h) > vb){
8367                     y = vb - h;
8368                     moved = true;
8369                 }
8370                 // then make sure top/left isn't negative
8371                 if(x < vx){
8372                     x = vx;
8373                     moved = true;
8374                 }
8375                 if(y < vy){
8376                     y = vy;
8377                     moved = true;
8378                 }
8379                 return moved ? [x, y] : false;
8380             };
8381         }(),
8382
8383         // private
8384         adjustForConstraints : function(xy, parent, offsets){
8385             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8386         },
8387
8388         /**
8389          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8390          * document it aligns it to the viewport.
8391          * The position parameter is optional, and can be specified in any one of the following formats:
8392          * <ul>
8393          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8394          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8395          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8396          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8397          *   <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
8398          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8399          * </ul>
8400          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8401          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8402          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8403          * that specified in order to enforce the viewport constraints.
8404          * Following are all of the supported anchor positions:
8405     <pre>
8406     Value  Description
8407     -----  -----------------------------
8408     tl     The top left corner (default)
8409     t      The center of the top edge
8410     tr     The top right corner
8411     l      The center of the left edge
8412     c      In the center of the element
8413     r      The center of the right edge
8414     bl     The bottom left corner
8415     b      The center of the bottom edge
8416     br     The bottom right corner
8417     </pre>
8418     Example Usage:
8419     <pre><code>
8420     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8421     el.alignTo("other-el");
8422
8423     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8424     el.alignTo("other-el", "tr?");
8425
8426     // align the bottom right corner of el with the center left edge of other-el
8427     el.alignTo("other-el", "br-l?");
8428
8429     // align the center of el with the bottom left corner of other-el and
8430     // adjust the x position by -6 pixels (and the y position by 0)
8431     el.alignTo("other-el", "c-bl", [-6, 0]);
8432     </code></pre>
8433          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8434          * @param {String} position The position to align to.
8435          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8436          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8437          * @return {Roo.Element} this
8438          */
8439         alignTo : function(element, position, offsets, animate){
8440             var xy = this.getAlignToXY(element, position, offsets);
8441             this.setXY(xy, this.preanim(arguments, 3));
8442             return this;
8443         },
8444
8445         /**
8446          * Anchors an element to another element and realigns it when the window is resized.
8447          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8448          * @param {String} position The position to align to.
8449          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8450          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8451          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8452          * is a number, it is used as the buffer delay (defaults to 50ms).
8453          * @param {Function} callback The function to call after the animation finishes
8454          * @return {Roo.Element} this
8455          */
8456         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8457             var action = function(){
8458                 this.alignTo(el, alignment, offsets, animate);
8459                 Roo.callback(callback, this);
8460             };
8461             Roo.EventManager.onWindowResize(action, this);
8462             var tm = typeof monitorScroll;
8463             if(tm != 'undefined'){
8464                 Roo.EventManager.on(window, 'scroll', action, this,
8465                     {buffer: tm == 'number' ? monitorScroll : 50});
8466             }
8467             action.call(this); // align immediately
8468             return this;
8469         },
8470         /**
8471          * Clears any opacity settings from this element. Required in some cases for IE.
8472          * @return {Roo.Element} this
8473          */
8474         clearOpacity : function(){
8475             if (window.ActiveXObject) {
8476                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8477                     this.dom.style.filter = "";
8478                 }
8479             } else {
8480                 this.dom.style.opacity = "";
8481                 this.dom.style["-moz-opacity"] = "";
8482                 this.dom.style["-khtml-opacity"] = "";
8483             }
8484             return this;
8485         },
8486
8487         /**
8488          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8489          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8490          * @return {Roo.Element} this
8491          */
8492         hide : function(animate){
8493             this.setVisible(false, this.preanim(arguments, 0));
8494             return this;
8495         },
8496
8497         /**
8498         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8499         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8500          * @return {Roo.Element} this
8501          */
8502         show : function(animate){
8503             this.setVisible(true, this.preanim(arguments, 0));
8504             return this;
8505         },
8506
8507         /**
8508          * @private Test if size has a unit, otherwise appends the default
8509          */
8510         addUnits : function(size){
8511             return Roo.Element.addUnits(size, this.defaultUnit);
8512         },
8513
8514         /**
8515          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8516          * @return {Roo.Element} this
8517          */
8518         beginMeasure : function(){
8519             var el = this.dom;
8520             if(el.offsetWidth || el.offsetHeight){
8521                 return this; // offsets work already
8522             }
8523             var changed = [];
8524             var p = this.dom, b = document.body; // start with this element
8525             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8526                 var pe = Roo.get(p);
8527                 if(pe.getStyle('display') == 'none'){
8528                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8529                     p.style.visibility = "hidden";
8530                     p.style.display = "block";
8531                 }
8532                 p = p.parentNode;
8533             }
8534             this._measureChanged = changed;
8535             return this;
8536
8537         },
8538
8539         /**
8540          * Restores displays to before beginMeasure was called
8541          * @return {Roo.Element} this
8542          */
8543         endMeasure : function(){
8544             var changed = this._measureChanged;
8545             if(changed){
8546                 for(var i = 0, len = changed.length; i < len; i++) {
8547                     var r = changed[i];
8548                     r.el.style.visibility = r.visibility;
8549                     r.el.style.display = "none";
8550                 }
8551                 this._measureChanged = null;
8552             }
8553             return this;
8554         },
8555
8556         /**
8557         * Update the innerHTML of this element, optionally searching for and processing scripts
8558         * @param {String} html The new HTML
8559         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8560         * @param {Function} callback For async script loading you can be noticed when the update completes
8561         * @return {Roo.Element} this
8562          */
8563         update : function(html, loadScripts, callback){
8564             if(typeof html == "undefined"){
8565                 html = "";
8566             }
8567             if(loadScripts !== true){
8568                 this.dom.innerHTML = html;
8569                 if(typeof callback == "function"){
8570                     callback();
8571                 }
8572                 return this;
8573             }
8574             var id = Roo.id();
8575             var dom = this.dom;
8576
8577             html += '<span id="' + id + '"></span>';
8578
8579             E.onAvailable(id, function(){
8580                 var hd = document.getElementsByTagName("head")[0];
8581                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8582                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8583                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8584
8585                 var match;
8586                 while(match = re.exec(html)){
8587                     var attrs = match[1];
8588                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8589                     if(srcMatch && srcMatch[2]){
8590                        var s = document.createElement("script");
8591                        s.src = srcMatch[2];
8592                        var typeMatch = attrs.match(typeRe);
8593                        if(typeMatch && typeMatch[2]){
8594                            s.type = typeMatch[2];
8595                        }
8596                        hd.appendChild(s);
8597                     }else if(match[2] && match[2].length > 0){
8598                         if(window.execScript) {
8599                            window.execScript(match[2]);
8600                         } else {
8601                             /**
8602                              * eval:var:id
8603                              * eval:var:dom
8604                              * eval:var:html
8605                              * 
8606                              */
8607                            window.eval(match[2]);
8608                         }
8609                     }
8610                 }
8611                 var el = document.getElementById(id);
8612                 if(el){el.parentNode.removeChild(el);}
8613                 if(typeof callback == "function"){
8614                     callback();
8615                 }
8616             });
8617             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8618             return this;
8619         },
8620
8621         /**
8622          * Direct access to the UpdateManager update() method (takes the same parameters).
8623          * @param {String/Function} url The url for this request or a function to call to get the url
8624          * @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}
8625          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8626          * @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.
8627          * @return {Roo.Element} this
8628          */
8629         load : function(){
8630             var um = this.getUpdateManager();
8631             um.update.apply(um, arguments);
8632             return this;
8633         },
8634
8635         /**
8636         * Gets this element's UpdateManager
8637         * @return {Roo.UpdateManager} The UpdateManager
8638         */
8639         getUpdateManager : function(){
8640             if(!this.updateManager){
8641                 this.updateManager = new Roo.UpdateManager(this);
8642             }
8643             return this.updateManager;
8644         },
8645
8646         /**
8647          * Disables text selection for this element (normalized across browsers)
8648          * @return {Roo.Element} this
8649          */
8650         unselectable : function(){
8651             this.dom.unselectable = "on";
8652             this.swallowEvent("selectstart", true);
8653             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8654             this.addClass("x-unselectable");
8655             return this;
8656         },
8657
8658         /**
8659         * Calculates the x, y to center this element on the screen
8660         * @return {Array} The x, y values [x, y]
8661         */
8662         getCenterXY : function(){
8663             return this.getAlignToXY(document, 'c-c');
8664         },
8665
8666         /**
8667         * Centers the Element in either the viewport, or another Element.
8668         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8669         */
8670         center : function(centerIn){
8671             this.alignTo(centerIn || document, 'c-c');
8672             return this;
8673         },
8674
8675         /**
8676          * Tests various css rules/browsers to determine if this element uses a border box
8677          * @return {Boolean}
8678          */
8679         isBorderBox : function(){
8680             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8681         },
8682
8683         /**
8684          * Return a box {x, y, width, height} that can be used to set another elements
8685          * size/location to match this element.
8686          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8687          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8688          * @return {Object} box An object in the format {x, y, width, height}
8689          */
8690         getBox : function(contentBox, local){
8691             var xy;
8692             if(!local){
8693                 xy = this.getXY();
8694             }else{
8695                 var left = parseInt(this.getStyle("left"), 10) || 0;
8696                 var top = parseInt(this.getStyle("top"), 10) || 0;
8697                 xy = [left, top];
8698             }
8699             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8700             if(!contentBox){
8701                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8702             }else{
8703                 var l = this.getBorderWidth("l")+this.getPadding("l");
8704                 var r = this.getBorderWidth("r")+this.getPadding("r");
8705                 var t = this.getBorderWidth("t")+this.getPadding("t");
8706                 var b = this.getBorderWidth("b")+this.getPadding("b");
8707                 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)};
8708             }
8709             bx.right = bx.x + bx.width;
8710             bx.bottom = bx.y + bx.height;
8711             return bx;
8712         },
8713
8714         /**
8715          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8716          for more information about the sides.
8717          * @param {String} sides
8718          * @return {Number}
8719          */
8720         getFrameWidth : function(sides, onlyContentBox){
8721             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8722         },
8723
8724         /**
8725          * 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.
8726          * @param {Object} box The box to fill {x, y, width, height}
8727          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8728          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8729          * @return {Roo.Element} this
8730          */
8731         setBox : function(box, adjust, animate){
8732             var w = box.width, h = box.height;
8733             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8734                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8735                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8736             }
8737             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8738             return this;
8739         },
8740
8741         /**
8742          * Forces the browser to repaint this element
8743          * @return {Roo.Element} this
8744          */
8745          repaint : function(){
8746             var dom = this.dom;
8747             this.addClass("x-repaint");
8748             setTimeout(function(){
8749                 Roo.get(dom).removeClass("x-repaint");
8750             }, 1);
8751             return this;
8752         },
8753
8754         /**
8755          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8756          * then it returns the calculated width of the sides (see getPadding)
8757          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8758          * @return {Object/Number}
8759          */
8760         getMargins : function(side){
8761             if(!side){
8762                 return {
8763                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8764                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8765                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8766                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8767                 };
8768             }else{
8769                 return this.addStyles(side, El.margins);
8770              }
8771         },
8772
8773         // private
8774         addStyles : function(sides, styles){
8775             var val = 0, v, w;
8776             for(var i = 0, len = sides.length; i < len; i++){
8777                 v = this.getStyle(styles[sides.charAt(i)]);
8778                 if(v){
8779                      w = parseInt(v, 10);
8780                      if(w){ val += w; }
8781                 }
8782             }
8783             return val;
8784         },
8785
8786         /**
8787          * Creates a proxy element of this element
8788          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8789          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8790          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8791          * @return {Roo.Element} The new proxy element
8792          */
8793         createProxy : function(config, renderTo, matchBox){
8794             if(renderTo){
8795                 renderTo = Roo.getDom(renderTo);
8796             }else{
8797                 renderTo = document.body;
8798             }
8799             config = typeof config == "object" ?
8800                 config : {tag : "div", cls: config};
8801             var proxy = Roo.DomHelper.append(renderTo, config, true);
8802             if(matchBox){
8803                proxy.setBox(this.getBox());
8804             }
8805             return proxy;
8806         },
8807
8808         /**
8809          * Puts a mask over this element to disable user interaction. Requires core.css.
8810          * This method can only be applied to elements which accept child nodes.
8811          * @param {String} msg (optional) A message to display in the mask
8812          * @param {String} msgCls (optional) A css class to apply to the msg element
8813          * @return {Element} The mask  element
8814          */
8815         mask : function(msg, msgCls){
8816             if(this.getStyle("position") == "static"){
8817                 this.setStyle("position", "relative");
8818             }
8819             if(!this._mask){
8820                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8821             }
8822             this.addClass("x-masked");
8823             this._mask.setDisplayed(true);
8824             if(typeof msg == 'string'){
8825                 if(!this._maskMsg){
8826                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8827                 }
8828                 var mm = this._maskMsg;
8829                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8830                 mm.dom.firstChild.innerHTML = msg;
8831                 mm.setDisplayed(true);
8832                 mm.center(this);
8833             }
8834             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8835                 this._mask.setHeight(this.getHeight());
8836             }
8837             return this._mask;
8838         },
8839
8840         /**
8841          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8842          * it is cached for reuse.
8843          */
8844         unmask : function(removeEl){
8845             if(this._mask){
8846                 if(removeEl === true){
8847                     this._mask.remove();
8848                     delete this._mask;
8849                     if(this._maskMsg){
8850                         this._maskMsg.remove();
8851                         delete this._maskMsg;
8852                     }
8853                 }else{
8854                     this._mask.setDisplayed(false);
8855                     if(this._maskMsg){
8856                         this._maskMsg.setDisplayed(false);
8857                     }
8858                 }
8859             }
8860             this.removeClass("x-masked");
8861         },
8862
8863         /**
8864          * Returns true if this element is masked
8865          * @return {Boolean}
8866          */
8867         isMasked : function(){
8868             return this._mask && this._mask.isVisible();
8869         },
8870
8871         /**
8872          * Creates an iframe shim for this element to keep selects and other windowed objects from
8873          * showing through.
8874          * @return {Roo.Element} The new shim element
8875          */
8876         createShim : function(){
8877             var el = document.createElement('iframe');
8878             el.frameBorder = 'no';
8879             el.className = 'roo-shim';
8880             if(Roo.isIE && Roo.isSecure){
8881                 el.src = Roo.SSL_SECURE_URL;
8882             }
8883             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8884             shim.autoBoxAdjust = false;
8885             return shim;
8886         },
8887
8888         /**
8889          * Removes this element from the DOM and deletes it from the cache
8890          */
8891         remove : function(){
8892             if(this.dom.parentNode){
8893                 this.dom.parentNode.removeChild(this.dom);
8894             }
8895             delete El.cache[this.dom.id];
8896         },
8897
8898         /**
8899          * Sets up event handlers to add and remove a css class when the mouse is over this element
8900          * @param {String} className
8901          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8902          * mouseout events for children elements
8903          * @return {Roo.Element} this
8904          */
8905         addClassOnOver : function(className, preventFlicker){
8906             this.on("mouseover", function(){
8907                 Roo.fly(this, '_internal').addClass(className);
8908             }, this.dom);
8909             var removeFn = function(e){
8910                 if(preventFlicker !== true || !e.within(this, true)){
8911                     Roo.fly(this, '_internal').removeClass(className);
8912                 }
8913             };
8914             this.on("mouseout", removeFn, this.dom);
8915             return this;
8916         },
8917
8918         /**
8919          * Sets up event handlers to add and remove a css class when this element has the focus
8920          * @param {String} className
8921          * @return {Roo.Element} this
8922          */
8923         addClassOnFocus : function(className){
8924             this.on("focus", function(){
8925                 Roo.fly(this, '_internal').addClass(className);
8926             }, this.dom);
8927             this.on("blur", function(){
8928                 Roo.fly(this, '_internal').removeClass(className);
8929             }, this.dom);
8930             return this;
8931         },
8932         /**
8933          * 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)
8934          * @param {String} className
8935          * @return {Roo.Element} this
8936          */
8937         addClassOnClick : function(className){
8938             var dom = this.dom;
8939             this.on("mousedown", function(){
8940                 Roo.fly(dom, '_internal').addClass(className);
8941                 var d = Roo.get(document);
8942                 var fn = function(){
8943                     Roo.fly(dom, '_internal').removeClass(className);
8944                     d.removeListener("mouseup", fn);
8945                 };
8946                 d.on("mouseup", fn);
8947             });
8948             return this;
8949         },
8950
8951         /**
8952          * Stops the specified event from bubbling and optionally prevents the default action
8953          * @param {String} eventName
8954          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8955          * @return {Roo.Element} this
8956          */
8957         swallowEvent : function(eventName, preventDefault){
8958             var fn = function(e){
8959                 e.stopPropagation();
8960                 if(preventDefault){
8961                     e.preventDefault();
8962                 }
8963             };
8964             if(eventName instanceof Array){
8965                 for(var i = 0, len = eventName.length; i < len; i++){
8966                      this.on(eventName[i], fn);
8967                 }
8968                 return this;
8969             }
8970             this.on(eventName, fn);
8971             return this;
8972         },
8973
8974         /**
8975          * @private
8976          */
8977       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8978
8979         /**
8980          * Sizes this element to its parent element's dimensions performing
8981          * neccessary box adjustments.
8982          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8983          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8984          * @return {Roo.Element} this
8985          */
8986         fitToParent : function(monitorResize, targetParent) {
8987           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8988           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8989           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8990             return;
8991           }
8992           var p = Roo.get(targetParent || this.dom.parentNode);
8993           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8994           if (monitorResize === true) {
8995             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8996             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8997           }
8998           return this;
8999         },
9000
9001         /**
9002          * Gets the next sibling, skipping text nodes
9003          * @return {HTMLElement} The next sibling or null
9004          */
9005         getNextSibling : function(){
9006             var n = this.dom.nextSibling;
9007             while(n && n.nodeType != 1){
9008                 n = n.nextSibling;
9009             }
9010             return n;
9011         },
9012
9013         /**
9014          * Gets the previous sibling, skipping text nodes
9015          * @return {HTMLElement} The previous sibling or null
9016          */
9017         getPrevSibling : function(){
9018             var n = this.dom.previousSibling;
9019             while(n && n.nodeType != 1){
9020                 n = n.previousSibling;
9021             }
9022             return n;
9023         },
9024
9025
9026         /**
9027          * Appends the passed element(s) to this element
9028          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9029          * @return {Roo.Element} this
9030          */
9031         appendChild: function(el){
9032             el = Roo.get(el);
9033             el.appendTo(this);
9034             return this;
9035         },
9036
9037         /**
9038          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9039          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9040          * automatically generated with the specified attributes.
9041          * @param {HTMLElement} insertBefore (optional) a child element of this element
9042          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9043          * @return {Roo.Element} The new child element
9044          */
9045         createChild: function(config, insertBefore, returnDom){
9046             config = config || {tag:'div'};
9047             if(insertBefore){
9048                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9049             }
9050             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9051         },
9052
9053         /**
9054          * Appends this element to the passed element
9055          * @param {String/HTMLElement/Element} el The new parent element
9056          * @return {Roo.Element} this
9057          */
9058         appendTo: function(el){
9059             el = Roo.getDom(el);
9060             el.appendChild(this.dom);
9061             return this;
9062         },
9063
9064         /**
9065          * Inserts this element before the passed element in the DOM
9066          * @param {String/HTMLElement/Element} el The element to insert before
9067          * @return {Roo.Element} this
9068          */
9069         insertBefore: function(el){
9070             el = Roo.getDom(el);
9071             el.parentNode.insertBefore(this.dom, el);
9072             return this;
9073         },
9074
9075         /**
9076          * Inserts this element after the passed element in the DOM
9077          * @param {String/HTMLElement/Element} el The element to insert after
9078          * @return {Roo.Element} this
9079          */
9080         insertAfter: function(el){
9081             el = Roo.getDom(el);
9082             el.parentNode.insertBefore(this.dom, el.nextSibling);
9083             return this;
9084         },
9085
9086         /**
9087          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9088          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9089          * @return {Roo.Element} The new child
9090          */
9091         insertFirst: function(el, returnDom){
9092             el = el || {};
9093             if(typeof el == 'object' && !el.nodeType){ // dh config
9094                 return this.createChild(el, this.dom.firstChild, returnDom);
9095             }else{
9096                 el = Roo.getDom(el);
9097                 this.dom.insertBefore(el, this.dom.firstChild);
9098                 return !returnDom ? Roo.get(el) : el;
9099             }
9100         },
9101
9102         /**
9103          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9104          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9105          * @param {String} where (optional) 'before' or 'after' defaults to before
9106          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9107          * @return {Roo.Element} the inserted Element
9108          */
9109         insertSibling: function(el, where, returnDom){
9110             where = where ? where.toLowerCase() : 'before';
9111             el = el || {};
9112             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9113
9114             if(typeof el == 'object' && !el.nodeType){ // dh config
9115                 if(where == 'after' && !this.dom.nextSibling){
9116                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9117                 }else{
9118                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9119                 }
9120
9121             }else{
9122                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9123                             where == 'before' ? this.dom : this.dom.nextSibling);
9124                 if(!returnDom){
9125                     rt = Roo.get(rt);
9126                 }
9127             }
9128             return rt;
9129         },
9130
9131         /**
9132          * Creates and wraps this element with another element
9133          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9134          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9135          * @return {HTMLElement/Element} The newly created wrapper element
9136          */
9137         wrap: function(config, returnDom){
9138             if(!config){
9139                 config = {tag: "div"};
9140             }
9141             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9142             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9143             return newEl;
9144         },
9145
9146         /**
9147          * Replaces the passed element with this element
9148          * @param {String/HTMLElement/Element} el The element to replace
9149          * @return {Roo.Element} this
9150          */
9151         replace: function(el){
9152             el = Roo.get(el);
9153             this.insertBefore(el);
9154             el.remove();
9155             return this;
9156         },
9157
9158         /**
9159          * Inserts an html fragment into this element
9160          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9161          * @param {String} html The HTML fragment
9162          * @param {Boolean} returnEl True to return an Roo.Element
9163          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9164          */
9165         insertHtml : function(where, html, returnEl){
9166             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9167             return returnEl ? Roo.get(el) : el;
9168         },
9169
9170         /**
9171          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9172          * @param {Object} o The object with the attributes
9173          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9174          * @return {Roo.Element} this
9175          */
9176         set : function(o, useSet){
9177             var el = this.dom;
9178             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9179             for(var attr in o){
9180                 if(attr == "style" || typeof o[attr] == "function") continue;
9181                 if(attr=="cls"){
9182                     el.className = o["cls"];
9183                 }else{
9184                     if(useSet) el.setAttribute(attr, o[attr]);
9185                     else el[attr] = o[attr];
9186                 }
9187             }
9188             if(o.style){
9189                 Roo.DomHelper.applyStyles(el, o.style);
9190             }
9191             return this;
9192         },
9193
9194         /**
9195          * Convenience method for constructing a KeyMap
9196          * @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:
9197          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9198          * @param {Function} fn The function to call
9199          * @param {Object} scope (optional) The scope of the function
9200          * @return {Roo.KeyMap} The KeyMap created
9201          */
9202         addKeyListener : function(key, fn, scope){
9203             var config;
9204             if(typeof key != "object" || key instanceof Array){
9205                 config = {
9206                     key: key,
9207                     fn: fn,
9208                     scope: scope
9209                 };
9210             }else{
9211                 config = {
9212                     key : key.key,
9213                     shift : key.shift,
9214                     ctrl : key.ctrl,
9215                     alt : key.alt,
9216                     fn: fn,
9217                     scope: scope
9218                 };
9219             }
9220             return new Roo.KeyMap(this, config);
9221         },
9222
9223         /**
9224          * Creates a KeyMap for this element
9225          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9226          * @return {Roo.KeyMap} The KeyMap created
9227          */
9228         addKeyMap : function(config){
9229             return new Roo.KeyMap(this, config);
9230         },
9231
9232         /**
9233          * Returns true if this element is scrollable.
9234          * @return {Boolean}
9235          */
9236          isScrollable : function(){
9237             var dom = this.dom;
9238             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9239         },
9240
9241         /**
9242          * 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().
9243          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9244          * @param {Number} value The new scroll value
9245          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9246          * @return {Element} this
9247          */
9248
9249         scrollTo : function(side, value, animate){
9250             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9251             if(!animate || !A){
9252                 this.dom[prop] = value;
9253             }else{
9254                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9255                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9256             }
9257             return this;
9258         },
9259
9260         /**
9261          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9262          * within this element's scrollable range.
9263          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9264          * @param {Number} distance How far to scroll the element in pixels
9265          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9266          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9267          * was scrolled as far as it could go.
9268          */
9269          scroll : function(direction, distance, animate){
9270              if(!this.isScrollable()){
9271                  return;
9272              }
9273              var el = this.dom;
9274              var l = el.scrollLeft, t = el.scrollTop;
9275              var w = el.scrollWidth, h = el.scrollHeight;
9276              var cw = el.clientWidth, ch = el.clientHeight;
9277              direction = direction.toLowerCase();
9278              var scrolled = false;
9279              var a = this.preanim(arguments, 2);
9280              switch(direction){
9281                  case "l":
9282                  case "left":
9283                      if(w - l > cw){
9284                          var v = Math.min(l + distance, w-cw);
9285                          this.scrollTo("left", v, a);
9286                          scrolled = true;
9287                      }
9288                      break;
9289                 case "r":
9290                 case "right":
9291                      if(l > 0){
9292                          var v = Math.max(l - distance, 0);
9293                          this.scrollTo("left", v, a);
9294                          scrolled = true;
9295                      }
9296                      break;
9297                 case "t":
9298                 case "top":
9299                 case "up":
9300                      if(t > 0){
9301                          var v = Math.max(t - distance, 0);
9302                          this.scrollTo("top", v, a);
9303                          scrolled = true;
9304                      }
9305                      break;
9306                 case "b":
9307                 case "bottom":
9308                 case "down":
9309                      if(h - t > ch){
9310                          var v = Math.min(t + distance, h-ch);
9311                          this.scrollTo("top", v, a);
9312                          scrolled = true;
9313                      }
9314                      break;
9315              }
9316              return scrolled;
9317         },
9318
9319         /**
9320          * Translates the passed page coordinates into left/top css values for this element
9321          * @param {Number/Array} x The page x or an array containing [x, y]
9322          * @param {Number} y The page y
9323          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9324          */
9325         translatePoints : function(x, y){
9326             if(typeof x == 'object' || x instanceof Array){
9327                 y = x[1]; x = x[0];
9328             }
9329             var p = this.getStyle('position');
9330             var o = this.getXY();
9331
9332             var l = parseInt(this.getStyle('left'), 10);
9333             var t = parseInt(this.getStyle('top'), 10);
9334
9335             if(isNaN(l)){
9336                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9337             }
9338             if(isNaN(t)){
9339                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9340             }
9341
9342             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9343         },
9344
9345         /**
9346          * Returns the current scroll position of the element.
9347          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9348          */
9349         getScroll : function(){
9350             var d = this.dom, doc = document;
9351             if(d == doc || d == doc.body){
9352                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9353                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9354                 return {left: l, top: t};
9355             }else{
9356                 return {left: d.scrollLeft, top: d.scrollTop};
9357             }
9358         },
9359
9360         /**
9361          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9362          * are convert to standard 6 digit hex color.
9363          * @param {String} attr The css attribute
9364          * @param {String} defaultValue The default value to use when a valid color isn't found
9365          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9366          * YUI color anims.
9367          */
9368         getColor : function(attr, defaultValue, prefix){
9369             var v = this.getStyle(attr);
9370             if(!v || v == "transparent" || v == "inherit") {
9371                 return defaultValue;
9372             }
9373             var color = typeof prefix == "undefined" ? "#" : prefix;
9374             if(v.substr(0, 4) == "rgb("){
9375                 var rvs = v.slice(4, v.length -1).split(",");
9376                 for(var i = 0; i < 3; i++){
9377                     var h = parseInt(rvs[i]).toString(16);
9378                     if(h < 16){
9379                         h = "0" + h;
9380                     }
9381                     color += h;
9382                 }
9383             } else {
9384                 if(v.substr(0, 1) == "#"){
9385                     if(v.length == 4) {
9386                         for(var i = 1; i < 4; i++){
9387                             var c = v.charAt(i);
9388                             color +=  c + c;
9389                         }
9390                     }else if(v.length == 7){
9391                         color += v.substr(1);
9392                     }
9393                 }
9394             }
9395             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9396         },
9397
9398         /**
9399          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9400          * gradient background, rounded corners and a 4-way shadow.
9401          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9402          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9403          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9404          * @return {Roo.Element} this
9405          */
9406         boxWrap : function(cls){
9407             cls = cls || 'x-box';
9408             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9409             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9410             return el;
9411         },
9412
9413         /**
9414          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9415          * @param {String} namespace The namespace in which to look for the attribute
9416          * @param {String} name The attribute name
9417          * @return {String} The attribute value
9418          */
9419         getAttributeNS : Roo.isIE ? function(ns, name){
9420             var d = this.dom;
9421             var type = typeof d[ns+":"+name];
9422             if(type != 'undefined' && type != 'unknown'){
9423                 return d[ns+":"+name];
9424             }
9425             return d[name];
9426         } : function(ns, name){
9427             var d = this.dom;
9428             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9429         }
9430     };
9431
9432     var ep = El.prototype;
9433
9434     /**
9435      * Appends an event handler (Shorthand for addListener)
9436      * @param {String}   eventName     The type of event to append
9437      * @param {Function} fn        The method the event invokes
9438      * @param {Object} scope       (optional) The scope (this object) of the fn
9439      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9440      * @method
9441      */
9442     ep.on = ep.addListener;
9443         // backwards compat
9444     ep.mon = ep.addListener;
9445
9446     /**
9447      * Removes an event handler from this element (shorthand for removeListener)
9448      * @param {String} eventName the type of event to remove
9449      * @param {Function} fn the method the event invokes
9450      * @return {Roo.Element} this
9451      * @method
9452      */
9453     ep.un = ep.removeListener;
9454
9455     /**
9456      * true to automatically adjust width and height settings for box-model issues (default to true)
9457      */
9458     ep.autoBoxAdjust = true;
9459
9460     // private
9461     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9462
9463     // private
9464     El.addUnits = function(v, defaultUnit){
9465         if(v === "" || v == "auto"){
9466             return v;
9467         }
9468         if(v === undefined){
9469             return '';
9470         }
9471         if(typeof v == "number" || !El.unitPattern.test(v)){
9472             return v + (defaultUnit || 'px');
9473         }
9474         return v;
9475     };
9476
9477     // special markup used throughout Roo when box wrapping elements
9478     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>';
9479     /**
9480      * Visibility mode constant - Use visibility to hide element
9481      * @static
9482      * @type Number
9483      */
9484     El.VISIBILITY = 1;
9485     /**
9486      * Visibility mode constant - Use display to hide element
9487      * @static
9488      * @type Number
9489      */
9490     El.DISPLAY = 2;
9491
9492     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9493     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9494     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9495
9496
9497
9498     /**
9499      * @private
9500      */
9501     El.cache = {};
9502
9503     var docEl;
9504
9505     /**
9506      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9507      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9508      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9509      * @return {Element} The Element object
9510      * @static
9511      */
9512     El.get = function(el){
9513         var ex, elm, id;
9514         if(!el){ return null; }
9515         if(typeof el == "string"){ // element id
9516             if(!(elm = document.getElementById(el))){
9517                 return null;
9518             }
9519             if(ex = El.cache[el]){
9520                 ex.dom = elm;
9521             }else{
9522                 ex = El.cache[el] = new El(elm);
9523             }
9524             return ex;
9525         }else if(el.tagName){ // dom element
9526             if(!(id = el.id)){
9527                 id = Roo.id(el);
9528             }
9529             if(ex = El.cache[id]){
9530                 ex.dom = el;
9531             }else{
9532                 ex = El.cache[id] = new El(el);
9533             }
9534             return ex;
9535         }else if(el instanceof El){
9536             if(el != docEl){
9537                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9538                                                               // catch case where it hasn't been appended
9539                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9540             }
9541             return el;
9542         }else if(el.isComposite){
9543             return el;
9544         }else if(el instanceof Array){
9545             return El.select(el);
9546         }else if(el == document){
9547             // create a bogus element object representing the document object
9548             if(!docEl){
9549                 var f = function(){};
9550                 f.prototype = El.prototype;
9551                 docEl = new f();
9552                 docEl.dom = document;
9553             }
9554             return docEl;
9555         }
9556         return null;
9557     };
9558
9559     // private
9560     El.uncache = function(el){
9561         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9562             if(a[i]){
9563                 delete El.cache[a[i].id || a[i]];
9564             }
9565         }
9566     };
9567
9568     // private
9569     // Garbage collection - uncache elements/purge listeners on orphaned elements
9570     // so we don't hold a reference and cause the browser to retain them
9571     El.garbageCollect = function(){
9572         if(!Roo.enableGarbageCollector){
9573             clearInterval(El.collectorThread);
9574             return;
9575         }
9576         for(var eid in El.cache){
9577             var el = El.cache[eid], d = el.dom;
9578             // -------------------------------------------------------
9579             // Determining what is garbage:
9580             // -------------------------------------------------------
9581             // !d
9582             // dom node is null, definitely garbage
9583             // -------------------------------------------------------
9584             // !d.parentNode
9585             // no parentNode == direct orphan, definitely garbage
9586             // -------------------------------------------------------
9587             // !d.offsetParent && !document.getElementById(eid)
9588             // display none elements have no offsetParent so we will
9589             // also try to look it up by it's id. However, check
9590             // offsetParent first so we don't do unneeded lookups.
9591             // This enables collection of elements that are not orphans
9592             // directly, but somewhere up the line they have an orphan
9593             // parent.
9594             // -------------------------------------------------------
9595             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9596                 delete El.cache[eid];
9597                 if(d && Roo.enableListenerCollection){
9598                     E.purgeElement(d);
9599                 }
9600             }
9601         }
9602     }
9603     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9604
9605
9606     // dom is optional
9607     El.Flyweight = function(dom){
9608         this.dom = dom;
9609     };
9610     El.Flyweight.prototype = El.prototype;
9611
9612     El._flyweights = {};
9613     /**
9614      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9615      * the dom node can be overwritten by other code.
9616      * @param {String/HTMLElement} el The dom node or id
9617      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9618      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9619      * @static
9620      * @return {Element} The shared Element object
9621      */
9622     El.fly = function(el, named){
9623         named = named || '_global';
9624         el = Roo.getDom(el);
9625         if(!el){
9626             return null;
9627         }
9628         if(!El._flyweights[named]){
9629             El._flyweights[named] = new El.Flyweight();
9630         }
9631         El._flyweights[named].dom = el;
9632         return El._flyweights[named];
9633     };
9634
9635     /**
9636      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9637      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9638      * Shorthand of {@link Roo.Element#get}
9639      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9640      * @return {Element} The Element object
9641      * @member Roo
9642      * @method get
9643      */
9644     Roo.get = El.get;
9645     /**
9646      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9647      * the dom node can be overwritten by other code.
9648      * Shorthand of {@link Roo.Element#fly}
9649      * @param {String/HTMLElement} el The dom node or id
9650      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9651      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9652      * @static
9653      * @return {Element} The shared Element object
9654      * @member Roo
9655      * @method fly
9656      */
9657     Roo.fly = El.fly;
9658
9659     // speedy lookup for elements never to box adjust
9660     var noBoxAdjust = Roo.isStrict ? {
9661         select:1
9662     } : {
9663         input:1, select:1, textarea:1
9664     };
9665     if(Roo.isIE || Roo.isGecko){
9666         noBoxAdjust['button'] = 1;
9667     }
9668
9669
9670     Roo.EventManager.on(window, 'unload', function(){
9671         delete El.cache;
9672         delete El._flyweights;
9673     });
9674 })();
9675
9676
9677
9678
9679 if(Roo.DomQuery){
9680     Roo.Element.selectorFunction = Roo.DomQuery.select;
9681 }
9682
9683 Roo.Element.select = function(selector, unique, root){
9684     var els;
9685     if(typeof selector == "string"){
9686         els = Roo.Element.selectorFunction(selector, root);
9687     }else if(selector.length !== undefined){
9688         els = selector;
9689     }else{
9690         throw "Invalid selector";
9691     }
9692     if(unique === true){
9693         return new Roo.CompositeElement(els);
9694     }else{
9695         return new Roo.CompositeElementLite(els);
9696     }
9697 };
9698 /**
9699  * Selects elements based on the passed CSS selector to enable working on them as 1.
9700  * @param {String/Array} selector The CSS selector or an array of elements
9701  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9702  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9703  * @return {CompositeElementLite/CompositeElement}
9704  * @member Roo
9705  * @method select
9706  */
9707 Roo.select = Roo.Element.select;
9708
9709
9710
9711
9712
9713
9714
9715
9716
9717
9718
9719
9720
9721
9722 /*
9723  * Based on:
9724  * Ext JS Library 1.1.1
9725  * Copyright(c) 2006-2007, Ext JS, LLC.
9726  *
9727  * Originally Released Under LGPL - original licence link has changed is not relivant.
9728  *
9729  * Fork - LGPL
9730  * <script type="text/javascript">
9731  */
9732
9733
9734
9735 //Notifies Element that fx methods are available
9736 Roo.enableFx = true;
9737
9738 /**
9739  * @class Roo.Fx
9740  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9741  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9742  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9743  * Element effects to work.</p><br/>
9744  *
9745  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9746  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9747  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9748  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9749  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9750  * expected results and should be done with care.</p><br/>
9751  *
9752  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9753  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9754 <pre>
9755 Value  Description
9756 -----  -----------------------------
9757 tl     The top left corner
9758 t      The center of the top edge
9759 tr     The top right corner
9760 l      The center of the left edge
9761 r      The center of the right edge
9762 bl     The bottom left corner
9763 b      The center of the bottom edge
9764 br     The bottom right corner
9765 </pre>
9766  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9767  * below are common options that can be passed to any Fx method.</b>
9768  * @cfg {Function} callback A function called when the effect is finished
9769  * @cfg {Object} scope The scope of the effect function
9770  * @cfg {String} easing A valid Easing value for the effect
9771  * @cfg {String} afterCls A css class to apply after the effect
9772  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9773  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9774  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9775  * effects that end with the element being visually hidden, ignored otherwise)
9776  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9777  * a function which returns such a specification that will be applied to the Element after the effect finishes
9778  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9779  * @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
9780  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9781  */
9782 Roo.Fx = {
9783         /**
9784          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9785          * origin for the slide effect.  This function automatically handles wrapping the element with
9786          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9787          * Usage:
9788          *<pre><code>
9789 // default: slide the element in from the top
9790 el.slideIn();
9791
9792 // custom: slide the element in from the right with a 2-second duration
9793 el.slideIn('r', { duration: 2 });
9794
9795 // common config options shown with default values
9796 el.slideIn('t', {
9797     easing: 'easeOut',
9798     duration: .5
9799 });
9800 </code></pre>
9801          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9802          * @param {Object} options (optional) Object literal with any of the Fx config options
9803          * @return {Roo.Element} The Element
9804          */
9805     slideIn : function(anchor, o){
9806         var el = this.getFxEl();
9807         o = o || {};
9808
9809         el.queueFx(o, function(){
9810
9811             anchor = anchor || "t";
9812
9813             // fix display to visibility
9814             this.fixDisplay();
9815
9816             // restore values after effect
9817             var r = this.getFxRestore();
9818             var b = this.getBox();
9819             // fixed size for slide
9820             this.setSize(b);
9821
9822             // wrap if needed
9823             var wrap = this.fxWrap(r.pos, o, "hidden");
9824
9825             var st = this.dom.style;
9826             st.visibility = "visible";
9827             st.position = "absolute";
9828
9829             // clear out temp styles after slide and unwrap
9830             var after = function(){
9831                 el.fxUnwrap(wrap, r.pos, o);
9832                 st.width = r.width;
9833                 st.height = r.height;
9834                 el.afterFx(o);
9835             };
9836             // time to calc the positions
9837             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9838
9839             switch(anchor.toLowerCase()){
9840                 case "t":
9841                     wrap.setSize(b.width, 0);
9842                     st.left = st.bottom = "0";
9843                     a = {height: bh};
9844                 break;
9845                 case "l":
9846                     wrap.setSize(0, b.height);
9847                     st.right = st.top = "0";
9848                     a = {width: bw};
9849                 break;
9850                 case "r":
9851                     wrap.setSize(0, b.height);
9852                     wrap.setX(b.right);
9853                     st.left = st.top = "0";
9854                     a = {width: bw, points: pt};
9855                 break;
9856                 case "b":
9857                     wrap.setSize(b.width, 0);
9858                     wrap.setY(b.bottom);
9859                     st.left = st.top = "0";
9860                     a = {height: bh, points: pt};
9861                 break;
9862                 case "tl":
9863                     wrap.setSize(0, 0);
9864                     st.right = st.bottom = "0";
9865                     a = {width: bw, height: bh};
9866                 break;
9867                 case "bl":
9868                     wrap.setSize(0, 0);
9869                     wrap.setY(b.y+b.height);
9870                     st.right = st.top = "0";
9871                     a = {width: bw, height: bh, points: pt};
9872                 break;
9873                 case "br":
9874                     wrap.setSize(0, 0);
9875                     wrap.setXY([b.right, b.bottom]);
9876                     st.left = st.top = "0";
9877                     a = {width: bw, height: bh, points: pt};
9878                 break;
9879                 case "tr":
9880                     wrap.setSize(0, 0);
9881                     wrap.setX(b.x+b.width);
9882                     st.left = st.bottom = "0";
9883                     a = {width: bw, height: bh, points: pt};
9884                 break;
9885             }
9886             this.dom.style.visibility = "visible";
9887             wrap.show();
9888
9889             arguments.callee.anim = wrap.fxanim(a,
9890                 o,
9891                 'motion',
9892                 .5,
9893                 'easeOut', after);
9894         });
9895         return this;
9896     },
9897     
9898         /**
9899          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9900          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9901          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9902          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9903          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9904          * Usage:
9905          *<pre><code>
9906 // default: slide the element out to the top
9907 el.slideOut();
9908
9909 // custom: slide the element out to the right with a 2-second duration
9910 el.slideOut('r', { duration: 2 });
9911
9912 // common config options shown with default values
9913 el.slideOut('t', {
9914     easing: 'easeOut',
9915     duration: .5,
9916     remove: false,
9917     useDisplay: false
9918 });
9919 </code></pre>
9920          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9921          * @param {Object} options (optional) Object literal with any of the Fx config options
9922          * @return {Roo.Element} The Element
9923          */
9924     slideOut : function(anchor, o){
9925         var el = this.getFxEl();
9926         o = o || {};
9927
9928         el.queueFx(o, function(){
9929
9930             anchor = anchor || "t";
9931
9932             // restore values after effect
9933             var r = this.getFxRestore();
9934             
9935             var b = this.getBox();
9936             // fixed size for slide
9937             this.setSize(b);
9938
9939             // wrap if needed
9940             var wrap = this.fxWrap(r.pos, o, "visible");
9941
9942             var st = this.dom.style;
9943             st.visibility = "visible";
9944             st.position = "absolute";
9945
9946             wrap.setSize(b);
9947
9948             var after = function(){
9949                 if(o.useDisplay){
9950                     el.setDisplayed(false);
9951                 }else{
9952                     el.hide();
9953                 }
9954
9955                 el.fxUnwrap(wrap, r.pos, o);
9956
9957                 st.width = r.width;
9958                 st.height = r.height;
9959
9960                 el.afterFx(o);
9961             };
9962
9963             var a, zero = {to: 0};
9964             switch(anchor.toLowerCase()){
9965                 case "t":
9966                     st.left = st.bottom = "0";
9967                     a = {height: zero};
9968                 break;
9969                 case "l":
9970                     st.right = st.top = "0";
9971                     a = {width: zero};
9972                 break;
9973                 case "r":
9974                     st.left = st.top = "0";
9975                     a = {width: zero, points: {to:[b.right, b.y]}};
9976                 break;
9977                 case "b":
9978                     st.left = st.top = "0";
9979                     a = {height: zero, points: {to:[b.x, b.bottom]}};
9980                 break;
9981                 case "tl":
9982                     st.right = st.bottom = "0";
9983                     a = {width: zero, height: zero};
9984                 break;
9985                 case "bl":
9986                     st.right = st.top = "0";
9987                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9988                 break;
9989                 case "br":
9990                     st.left = st.top = "0";
9991                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9992                 break;
9993                 case "tr":
9994                     st.left = st.bottom = "0";
9995                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9996                 break;
9997             }
9998
9999             arguments.callee.anim = wrap.fxanim(a,
10000                 o,
10001                 'motion',
10002                 .5,
10003                 "easeOut", after);
10004         });
10005         return this;
10006     },
10007
10008         /**
10009          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10010          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10011          * The element must be removed from the DOM using the 'remove' config option if desired.
10012          * Usage:
10013          *<pre><code>
10014 // default
10015 el.puff();
10016
10017 // common config options shown with default values
10018 el.puff({
10019     easing: 'easeOut',
10020     duration: .5,
10021     remove: false,
10022     useDisplay: false
10023 });
10024 </code></pre>
10025          * @param {Object} options (optional) Object literal with any of the Fx config options
10026          * @return {Roo.Element} The Element
10027          */
10028     puff : function(o){
10029         var el = this.getFxEl();
10030         o = o || {};
10031
10032         el.queueFx(o, function(){
10033             this.clearOpacity();
10034             this.show();
10035
10036             // restore values after effect
10037             var r = this.getFxRestore();
10038             var st = this.dom.style;
10039
10040             var after = function(){
10041                 if(o.useDisplay){
10042                     el.setDisplayed(false);
10043                 }else{
10044                     el.hide();
10045                 }
10046
10047                 el.clearOpacity();
10048
10049                 el.setPositioning(r.pos);
10050                 st.width = r.width;
10051                 st.height = r.height;
10052                 st.fontSize = '';
10053                 el.afterFx(o);
10054             };
10055
10056             var width = this.getWidth();
10057             var height = this.getHeight();
10058
10059             arguments.callee.anim = this.fxanim({
10060                     width : {to: this.adjustWidth(width * 2)},
10061                     height : {to: this.adjustHeight(height * 2)},
10062                     points : {by: [-(width * .5), -(height * .5)]},
10063                     opacity : {to: 0},
10064                     fontSize: {to:200, unit: "%"}
10065                 },
10066                 o,
10067                 'motion',
10068                 .5,
10069                 "easeOut", after);
10070         });
10071         return this;
10072     },
10073
10074         /**
10075          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10076          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10077          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10078          * Usage:
10079          *<pre><code>
10080 // default
10081 el.switchOff();
10082
10083 // all config options shown with default values
10084 el.switchOff({
10085     easing: 'easeIn',
10086     duration: .3,
10087     remove: false,
10088     useDisplay: false
10089 });
10090 </code></pre>
10091          * @param {Object} options (optional) Object literal with any of the Fx config options
10092          * @return {Roo.Element} The Element
10093          */
10094     switchOff : function(o){
10095         var el = this.getFxEl();
10096         o = o || {};
10097
10098         el.queueFx(o, function(){
10099             this.clearOpacity();
10100             this.clip();
10101
10102             // restore values after effect
10103             var r = this.getFxRestore();
10104             var st = this.dom.style;
10105
10106             var after = function(){
10107                 if(o.useDisplay){
10108                     el.setDisplayed(false);
10109                 }else{
10110                     el.hide();
10111                 }
10112
10113                 el.clearOpacity();
10114                 el.setPositioning(r.pos);
10115                 st.width = r.width;
10116                 st.height = r.height;
10117
10118                 el.afterFx(o);
10119             };
10120
10121             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10122                 this.clearOpacity();
10123                 (function(){
10124                     this.fxanim({
10125                         height:{to:1},
10126                         points:{by:[0, this.getHeight() * .5]}
10127                     }, o, 'motion', 0.3, 'easeIn', after);
10128                 }).defer(100, this);
10129             });
10130         });
10131         return this;
10132     },
10133
10134     /**
10135      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10136      * changed using the "attr" config option) and then fading back to the original color. If no original
10137      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10138      * Usage:
10139 <pre><code>
10140 // default: highlight background to yellow
10141 el.highlight();
10142
10143 // custom: highlight foreground text to blue for 2 seconds
10144 el.highlight("0000ff", { attr: 'color', duration: 2 });
10145
10146 // common config options shown with default values
10147 el.highlight("ffff9c", {
10148     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10149     endColor: (current color) or "ffffff",
10150     easing: 'easeIn',
10151     duration: 1
10152 });
10153 </code></pre>
10154      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10155      * @param {Object} options (optional) Object literal with any of the Fx config options
10156      * @return {Roo.Element} The Element
10157      */ 
10158     highlight : function(color, o){
10159         var el = this.getFxEl();
10160         o = o || {};
10161
10162         el.queueFx(o, function(){
10163             color = color || "ffff9c";
10164             attr = o.attr || "backgroundColor";
10165
10166             this.clearOpacity();
10167             this.show();
10168
10169             var origColor = this.getColor(attr);
10170             var restoreColor = this.dom.style[attr];
10171             endColor = (o.endColor || origColor) || "ffffff";
10172
10173             var after = function(){
10174                 el.dom.style[attr] = restoreColor;
10175                 el.afterFx(o);
10176             };
10177
10178             var a = {};
10179             a[attr] = {from: color, to: endColor};
10180             arguments.callee.anim = this.fxanim(a,
10181                 o,
10182                 'color',
10183                 1,
10184                 'easeIn', after);
10185         });
10186         return this;
10187     },
10188
10189    /**
10190     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10191     * Usage:
10192 <pre><code>
10193 // default: a single light blue ripple
10194 el.frame();
10195
10196 // custom: 3 red ripples lasting 3 seconds total
10197 el.frame("ff0000", 3, { duration: 3 });
10198
10199 // common config options shown with default values
10200 el.frame("C3DAF9", 1, {
10201     duration: 1 //duration of entire animation (not each individual ripple)
10202     // Note: Easing is not configurable and will be ignored if included
10203 });
10204 </code></pre>
10205     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10206     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10207     * @param {Object} options (optional) Object literal with any of the Fx config options
10208     * @return {Roo.Element} The Element
10209     */
10210     frame : function(color, count, o){
10211         var el = this.getFxEl();
10212         o = o || {};
10213
10214         el.queueFx(o, function(){
10215             color = color || "#C3DAF9";
10216             if(color.length == 6){
10217                 color = "#" + color;
10218             }
10219             count = count || 1;
10220             duration = o.duration || 1;
10221             this.show();
10222
10223             var b = this.getBox();
10224             var animFn = function(){
10225                 var proxy = this.createProxy({
10226
10227                      style:{
10228                         visbility:"hidden",
10229                         position:"absolute",
10230                         "z-index":"35000", // yee haw
10231                         border:"0px solid " + color
10232                      }
10233                   });
10234                 var scale = Roo.isBorderBox ? 2 : 1;
10235                 proxy.animate({
10236                     top:{from:b.y, to:b.y - 20},
10237                     left:{from:b.x, to:b.x - 20},
10238                     borderWidth:{from:0, to:10},
10239                     opacity:{from:1, to:0},
10240                     height:{from:b.height, to:(b.height + (20*scale))},
10241                     width:{from:b.width, to:(b.width + (20*scale))}
10242                 }, duration, function(){
10243                     proxy.remove();
10244                 });
10245                 if(--count > 0){
10246                      animFn.defer((duration/2)*1000, this);
10247                 }else{
10248                     el.afterFx(o);
10249                 }
10250             };
10251             animFn.call(this);
10252         });
10253         return this;
10254     },
10255
10256    /**
10257     * Creates a pause before any subsequent queued effects begin.  If there are
10258     * no effects queued after the pause it will have no effect.
10259     * Usage:
10260 <pre><code>
10261 el.pause(1);
10262 </code></pre>
10263     * @param {Number} seconds The length of time to pause (in seconds)
10264     * @return {Roo.Element} The Element
10265     */
10266     pause : function(seconds){
10267         var el = this.getFxEl();
10268         var o = {};
10269
10270         el.queueFx(o, function(){
10271             setTimeout(function(){
10272                 el.afterFx(o);
10273             }, seconds * 1000);
10274         });
10275         return this;
10276     },
10277
10278    /**
10279     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10280     * using the "endOpacity" config option.
10281     * Usage:
10282 <pre><code>
10283 // default: fade in from opacity 0 to 100%
10284 el.fadeIn();
10285
10286 // custom: fade in from opacity 0 to 75% over 2 seconds
10287 el.fadeIn({ endOpacity: .75, duration: 2});
10288
10289 // common config options shown with default values
10290 el.fadeIn({
10291     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10292     easing: 'easeOut',
10293     duration: .5
10294 });
10295 </code></pre>
10296     * @param {Object} options (optional) Object literal with any of the Fx config options
10297     * @return {Roo.Element} The Element
10298     */
10299     fadeIn : function(o){
10300         var el = this.getFxEl();
10301         o = o || {};
10302         el.queueFx(o, function(){
10303             this.setOpacity(0);
10304             this.fixDisplay();
10305             this.dom.style.visibility = 'visible';
10306             var to = o.endOpacity || 1;
10307             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10308                 o, null, .5, "easeOut", function(){
10309                 if(to == 1){
10310                     this.clearOpacity();
10311                 }
10312                 el.afterFx(o);
10313             });
10314         });
10315         return this;
10316     },
10317
10318    /**
10319     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10320     * using the "endOpacity" config option.
10321     * Usage:
10322 <pre><code>
10323 // default: fade out from the element's current opacity to 0
10324 el.fadeOut();
10325
10326 // custom: fade out from the element's current opacity to 25% over 2 seconds
10327 el.fadeOut({ endOpacity: .25, duration: 2});
10328
10329 // common config options shown with default values
10330 el.fadeOut({
10331     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10332     easing: 'easeOut',
10333     duration: .5
10334     remove: false,
10335     useDisplay: false
10336 });
10337 </code></pre>
10338     * @param {Object} options (optional) Object literal with any of the Fx config options
10339     * @return {Roo.Element} The Element
10340     */
10341     fadeOut : function(o){
10342         var el = this.getFxEl();
10343         o = o || {};
10344         el.queueFx(o, function(){
10345             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10346                 o, null, .5, "easeOut", function(){
10347                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10348                      this.dom.style.display = "none";
10349                 }else{
10350                      this.dom.style.visibility = "hidden";
10351                 }
10352                 this.clearOpacity();
10353                 el.afterFx(o);
10354             });
10355         });
10356         return this;
10357     },
10358
10359    /**
10360     * Animates the transition of an element's dimensions from a starting height/width
10361     * to an ending height/width.
10362     * Usage:
10363 <pre><code>
10364 // change height and width to 100x100 pixels
10365 el.scale(100, 100);
10366
10367 // common config options shown with default values.  The height and width will default to
10368 // the element's existing values if passed as null.
10369 el.scale(
10370     [element's width],
10371     [element's height], {
10372     easing: 'easeOut',
10373     duration: .35
10374 });
10375 </code></pre>
10376     * @param {Number} width  The new width (pass undefined to keep the original width)
10377     * @param {Number} height  The new height (pass undefined to keep the original height)
10378     * @param {Object} options (optional) Object literal with any of the Fx config options
10379     * @return {Roo.Element} The Element
10380     */
10381     scale : function(w, h, o){
10382         this.shift(Roo.apply({}, o, {
10383             width: w,
10384             height: h
10385         }));
10386         return this;
10387     },
10388
10389    /**
10390     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10391     * Any of these properties not specified in the config object will not be changed.  This effect 
10392     * requires that at least one new dimension, position or opacity setting must be passed in on
10393     * the config object in order for the function to have any effect.
10394     * Usage:
10395 <pre><code>
10396 // slide the element horizontally to x position 200 while changing the height and opacity
10397 el.shift({ x: 200, height: 50, opacity: .8 });
10398
10399 // common config options shown with default values.
10400 el.shift({
10401     width: [element's width],
10402     height: [element's height],
10403     x: [element's x position],
10404     y: [element's y position],
10405     opacity: [element's opacity],
10406     easing: 'easeOut',
10407     duration: .35
10408 });
10409 </code></pre>
10410     * @param {Object} options  Object literal with any of the Fx config options
10411     * @return {Roo.Element} The Element
10412     */
10413     shift : function(o){
10414         var el = this.getFxEl();
10415         o = o || {};
10416         el.queueFx(o, function(){
10417             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10418             if(w !== undefined){
10419                 a.width = {to: this.adjustWidth(w)};
10420             }
10421             if(h !== undefined){
10422                 a.height = {to: this.adjustHeight(h)};
10423             }
10424             if(x !== undefined || y !== undefined){
10425                 a.points = {to: [
10426                     x !== undefined ? x : this.getX(),
10427                     y !== undefined ? y : this.getY()
10428                 ]};
10429             }
10430             if(op !== undefined){
10431                 a.opacity = {to: op};
10432             }
10433             if(o.xy !== undefined){
10434                 a.points = {to: o.xy};
10435             }
10436             arguments.callee.anim = this.fxanim(a,
10437                 o, 'motion', .35, "easeOut", function(){
10438                 el.afterFx(o);
10439             });
10440         });
10441         return this;
10442     },
10443
10444         /**
10445          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10446          * ending point of the effect.
10447          * Usage:
10448          *<pre><code>
10449 // default: slide the element downward while fading out
10450 el.ghost();
10451
10452 // custom: slide the element out to the right with a 2-second duration
10453 el.ghost('r', { duration: 2 });
10454
10455 // common config options shown with default values
10456 el.ghost('b', {
10457     easing: 'easeOut',
10458     duration: .5
10459     remove: false,
10460     useDisplay: false
10461 });
10462 </code></pre>
10463          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10464          * @param {Object} options (optional) Object literal with any of the Fx config options
10465          * @return {Roo.Element} The Element
10466          */
10467     ghost : function(anchor, o){
10468         var el = this.getFxEl();
10469         o = o || {};
10470
10471         el.queueFx(o, function(){
10472             anchor = anchor || "b";
10473
10474             // restore values after effect
10475             var r = this.getFxRestore();
10476             var w = this.getWidth(),
10477                 h = this.getHeight();
10478
10479             var st = this.dom.style;
10480
10481             var after = function(){
10482                 if(o.useDisplay){
10483                     el.setDisplayed(false);
10484                 }else{
10485                     el.hide();
10486                 }
10487
10488                 el.clearOpacity();
10489                 el.setPositioning(r.pos);
10490                 st.width = r.width;
10491                 st.height = r.height;
10492
10493                 el.afterFx(o);
10494             };
10495
10496             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10497             switch(anchor.toLowerCase()){
10498                 case "t":
10499                     pt.by = [0, -h];
10500                 break;
10501                 case "l":
10502                     pt.by = [-w, 0];
10503                 break;
10504                 case "r":
10505                     pt.by = [w, 0];
10506                 break;
10507                 case "b":
10508                     pt.by = [0, h];
10509                 break;
10510                 case "tl":
10511                     pt.by = [-w, -h];
10512                 break;
10513                 case "bl":
10514                     pt.by = [-w, h];
10515                 break;
10516                 case "br":
10517                     pt.by = [w, h];
10518                 break;
10519                 case "tr":
10520                     pt.by = [w, -h];
10521                 break;
10522             }
10523
10524             arguments.callee.anim = this.fxanim(a,
10525                 o,
10526                 'motion',
10527                 .5,
10528                 "easeOut", after);
10529         });
10530         return this;
10531     },
10532
10533         /**
10534          * Ensures that all effects queued after syncFx is called on the element are
10535          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10536          * @return {Roo.Element} The Element
10537          */
10538     syncFx : function(){
10539         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10540             block : false,
10541             concurrent : true,
10542             stopFx : false
10543         });
10544         return this;
10545     },
10546
10547         /**
10548          * Ensures that all effects queued after sequenceFx is called on the element are
10549          * run in sequence.  This is the opposite of {@link #syncFx}.
10550          * @return {Roo.Element} The Element
10551          */
10552     sequenceFx : function(){
10553         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10554             block : false,
10555             concurrent : false,
10556             stopFx : false
10557         });
10558         return this;
10559     },
10560
10561         /* @private */
10562     nextFx : function(){
10563         var ef = this.fxQueue[0];
10564         if(ef){
10565             ef.call(this);
10566         }
10567     },
10568
10569         /**
10570          * Returns true if the element has any effects actively running or queued, else returns false.
10571          * @return {Boolean} True if element has active effects, else false
10572          */
10573     hasActiveFx : function(){
10574         return this.fxQueue && this.fxQueue[0];
10575     },
10576
10577         /**
10578          * Stops any running effects and clears the element's internal effects queue if it contains
10579          * any additional effects that haven't started yet.
10580          * @return {Roo.Element} The Element
10581          */
10582     stopFx : function(){
10583         if(this.hasActiveFx()){
10584             var cur = this.fxQueue[0];
10585             if(cur && cur.anim && cur.anim.isAnimated()){
10586                 this.fxQueue = [cur]; // clear out others
10587                 cur.anim.stop(true);
10588             }
10589         }
10590         return this;
10591     },
10592
10593         /* @private */
10594     beforeFx : function(o){
10595         if(this.hasActiveFx() && !o.concurrent){
10596            if(o.stopFx){
10597                this.stopFx();
10598                return true;
10599            }
10600            return false;
10601         }
10602         return true;
10603     },
10604
10605         /**
10606          * Returns true if the element is currently blocking so that no other effect can be queued
10607          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10608          * used to ensure that an effect initiated by a user action runs to completion prior to the
10609          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10610          * @return {Boolean} True if blocking, else false
10611          */
10612     hasFxBlock : function(){
10613         var q = this.fxQueue;
10614         return q && q[0] && q[0].block;
10615     },
10616
10617         /* @private */
10618     queueFx : function(o, fn){
10619         if(!this.fxQueue){
10620             this.fxQueue = [];
10621         }
10622         if(!this.hasFxBlock()){
10623             Roo.applyIf(o, this.fxDefaults);
10624             if(!o.concurrent){
10625                 var run = this.beforeFx(o);
10626                 fn.block = o.block;
10627                 this.fxQueue.push(fn);
10628                 if(run){
10629                     this.nextFx();
10630                 }
10631             }else{
10632                 fn.call(this);
10633             }
10634         }
10635         return this;
10636     },
10637
10638         /* @private */
10639     fxWrap : function(pos, o, vis){
10640         var wrap;
10641         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10642             var wrapXY;
10643             if(o.fixPosition){
10644                 wrapXY = this.getXY();
10645             }
10646             var div = document.createElement("div");
10647             div.style.visibility = vis;
10648             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10649             wrap.setPositioning(pos);
10650             if(wrap.getStyle("position") == "static"){
10651                 wrap.position("relative");
10652             }
10653             this.clearPositioning('auto');
10654             wrap.clip();
10655             wrap.dom.appendChild(this.dom);
10656             if(wrapXY){
10657                 wrap.setXY(wrapXY);
10658             }
10659         }
10660         return wrap;
10661     },
10662
10663         /* @private */
10664     fxUnwrap : function(wrap, pos, o){
10665         this.clearPositioning();
10666         this.setPositioning(pos);
10667         if(!o.wrap){
10668             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10669             wrap.remove();
10670         }
10671     },
10672
10673         /* @private */
10674     getFxRestore : function(){
10675         var st = this.dom.style;
10676         return {pos: this.getPositioning(), width: st.width, height : st.height};
10677     },
10678
10679         /* @private */
10680     afterFx : function(o){
10681         if(o.afterStyle){
10682             this.applyStyles(o.afterStyle);
10683         }
10684         if(o.afterCls){
10685             this.addClass(o.afterCls);
10686         }
10687         if(o.remove === true){
10688             this.remove();
10689         }
10690         Roo.callback(o.callback, o.scope, [this]);
10691         if(!o.concurrent){
10692             this.fxQueue.shift();
10693             this.nextFx();
10694         }
10695     },
10696
10697         /* @private */
10698     getFxEl : function(){ // support for composite element fx
10699         return Roo.get(this.dom);
10700     },
10701
10702         /* @private */
10703     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10704         animType = animType || 'run';
10705         opt = opt || {};
10706         var anim = Roo.lib.Anim[animType](
10707             this.dom, args,
10708             (opt.duration || defaultDur) || .35,
10709             (opt.easing || defaultEase) || 'easeOut',
10710             function(){
10711                 Roo.callback(cb, this);
10712             },
10713             this
10714         );
10715         opt.anim = anim;
10716         return anim;
10717     }
10718 };
10719
10720 // backwords compat
10721 Roo.Fx.resize = Roo.Fx.scale;
10722
10723 //When included, Roo.Fx is automatically applied to Element so that all basic
10724 //effects are available directly via the Element API
10725 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10726  * Based on:
10727  * Ext JS Library 1.1.1
10728  * Copyright(c) 2006-2007, Ext JS, LLC.
10729  *
10730  * Originally Released Under LGPL - original licence link has changed is not relivant.
10731  *
10732  * Fork - LGPL
10733  * <script type="text/javascript">
10734  */
10735
10736
10737 /**
10738  * @class Roo.CompositeElement
10739  * Standard composite class. Creates a Roo.Element for every element in the collection.
10740  * <br><br>
10741  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10742  * actions will be performed on all the elements in this collection.</b>
10743  * <br><br>
10744  * All methods return <i>this</i> and can be chained.
10745  <pre><code>
10746  var els = Roo.select("#some-el div.some-class", true);
10747  // or select directly from an existing element
10748  var el = Roo.get('some-el');
10749  el.select('div.some-class', true);
10750
10751  els.setWidth(100); // all elements become 100 width
10752  els.hide(true); // all elements fade out and hide
10753  // or
10754  els.setWidth(100).hide(true);
10755  </code></pre>
10756  */
10757 Roo.CompositeElement = function(els){
10758     this.elements = [];
10759     this.addElements(els);
10760 };
10761 Roo.CompositeElement.prototype = {
10762     isComposite: true,
10763     addElements : function(els){
10764         if(!els) return this;
10765         if(typeof els == "string"){
10766             els = Roo.Element.selectorFunction(els);
10767         }
10768         var yels = this.elements;
10769         var index = yels.length-1;
10770         for(var i = 0, len = els.length; i < len; i++) {
10771                 yels[++index] = Roo.get(els[i]);
10772         }
10773         return this;
10774     },
10775
10776     /**
10777     * Clears this composite and adds the elements returned by the passed selector.
10778     * @param {String/Array} els A string CSS selector, an array of elements or an element
10779     * @return {CompositeElement} this
10780     */
10781     fill : function(els){
10782         this.elements = [];
10783         this.add(els);
10784         return this;
10785     },
10786
10787     /**
10788     * Filters this composite to only elements that match the passed selector.
10789     * @param {String} selector A string CSS selector
10790     * @return {CompositeElement} this
10791     */
10792     filter : function(selector){
10793         var els = [];
10794         this.each(function(el){
10795             if(el.is(selector)){
10796                 els[els.length] = el.dom;
10797             }
10798         });
10799         this.fill(els);
10800         return this;
10801     },
10802
10803     invoke : function(fn, args){
10804         var els = this.elements;
10805         for(var i = 0, len = els.length; i < len; i++) {
10806                 Roo.Element.prototype[fn].apply(els[i], args);
10807         }
10808         return this;
10809     },
10810     /**
10811     * Adds elements to this composite.
10812     * @param {String/Array} els A string CSS selector, an array of elements or an element
10813     * @return {CompositeElement} this
10814     */
10815     add : function(els){
10816         if(typeof els == "string"){
10817             this.addElements(Roo.Element.selectorFunction(els));
10818         }else if(els.length !== undefined){
10819             this.addElements(els);
10820         }else{
10821             this.addElements([els]);
10822         }
10823         return this;
10824     },
10825     /**
10826     * Calls the passed function passing (el, this, index) for each element in this composite.
10827     * @param {Function} fn The function to call
10828     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10829     * @return {CompositeElement} this
10830     */
10831     each : function(fn, scope){
10832         var els = this.elements;
10833         for(var i = 0, len = els.length; i < len; i++){
10834             if(fn.call(scope || els[i], els[i], this, i) === false) {
10835                 break;
10836             }
10837         }
10838         return this;
10839     },
10840
10841     /**
10842      * Returns the Element object at the specified index
10843      * @param {Number} index
10844      * @return {Roo.Element}
10845      */
10846     item : function(index){
10847         return this.elements[index] || null;
10848     },
10849
10850     /**
10851      * Returns the first Element
10852      * @return {Roo.Element}
10853      */
10854     first : function(){
10855         return this.item(0);
10856     },
10857
10858     /**
10859      * Returns the last Element
10860      * @return {Roo.Element}
10861      */
10862     last : function(){
10863         return this.item(this.elements.length-1);
10864     },
10865
10866     /**
10867      * Returns the number of elements in this composite
10868      * @return Number
10869      */
10870     getCount : function(){
10871         return this.elements.length;
10872     },
10873
10874     /**
10875      * Returns true if this composite contains the passed element
10876      * @return Boolean
10877      */
10878     contains : function(el){
10879         return this.indexOf(el) !== -1;
10880     },
10881
10882     /**
10883      * Returns true if this composite contains the passed element
10884      * @return Boolean
10885      */
10886     indexOf : function(el){
10887         return this.elements.indexOf(Roo.get(el));
10888     },
10889
10890
10891     /**
10892     * Removes the specified element(s).
10893     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10894     * or an array of any of those.
10895     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10896     * @return {CompositeElement} this
10897     */
10898     removeElement : function(el, removeDom){
10899         if(el instanceof Array){
10900             for(var i = 0, len = el.length; i < len; i++){
10901                 this.removeElement(el[i]);
10902             }
10903             return this;
10904         }
10905         var index = typeof el == 'number' ? el : this.indexOf(el);
10906         if(index !== -1){
10907             if(removeDom){
10908                 var d = this.elements[index];
10909                 if(d.dom){
10910                     d.remove();
10911                 }else{
10912                     d.parentNode.removeChild(d);
10913                 }
10914             }
10915             this.elements.splice(index, 1);
10916         }
10917         return this;
10918     },
10919
10920     /**
10921     * Replaces the specified element with the passed element.
10922     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10923     * to replace.
10924     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10925     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10926     * @return {CompositeElement} this
10927     */
10928     replaceElement : function(el, replacement, domReplace){
10929         var index = typeof el == 'number' ? el : this.indexOf(el);
10930         if(index !== -1){
10931             if(domReplace){
10932                 this.elements[index].replaceWith(replacement);
10933             }else{
10934                 this.elements.splice(index, 1, Roo.get(replacement))
10935             }
10936         }
10937         return this;
10938     },
10939
10940     /**
10941      * Removes all elements.
10942      */
10943     clear : function(){
10944         this.elements = [];
10945     }
10946 };
10947 (function(){
10948     Roo.CompositeElement.createCall = function(proto, fnName){
10949         if(!proto[fnName]){
10950             proto[fnName] = function(){
10951                 return this.invoke(fnName, arguments);
10952             };
10953         }
10954     };
10955     for(var fnName in Roo.Element.prototype){
10956         if(typeof Roo.Element.prototype[fnName] == "function"){
10957             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10958         }
10959     };
10960 })();
10961 /*
10962  * Based on:
10963  * Ext JS Library 1.1.1
10964  * Copyright(c) 2006-2007, Ext JS, LLC.
10965  *
10966  * Originally Released Under LGPL - original licence link has changed is not relivant.
10967  *
10968  * Fork - LGPL
10969  * <script type="text/javascript">
10970  */
10971
10972 /**
10973  * @class Roo.CompositeElementLite
10974  * @extends Roo.CompositeElement
10975  * Flyweight composite class. Reuses the same Roo.Element for element operations.
10976  <pre><code>
10977  var els = Roo.select("#some-el div.some-class");
10978  // or select directly from an existing element
10979  var el = Roo.get('some-el');
10980  el.select('div.some-class');
10981
10982  els.setWidth(100); // all elements become 100 width
10983  els.hide(true); // all elements fade out and hide
10984  // or
10985  els.setWidth(100).hide(true);
10986  </code></pre><br><br>
10987  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10988  * actions will be performed on all the elements in this collection.</b>
10989  */
10990 Roo.CompositeElementLite = function(els){
10991     Roo.CompositeElementLite.superclass.constructor.call(this, els);
10992     this.el = new Roo.Element.Flyweight();
10993 };
10994 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10995     addElements : function(els){
10996         if(els){
10997             if(els instanceof Array){
10998                 this.elements = this.elements.concat(els);
10999             }else{
11000                 var yels = this.elements;
11001                 var index = yels.length-1;
11002                 for(var i = 0, len = els.length; i < len; i++) {
11003                     yels[++index] = els[i];
11004                 }
11005             }
11006         }
11007         return this;
11008     },
11009     invoke : function(fn, args){
11010         var els = this.elements;
11011         var el = this.el;
11012         for(var i = 0, len = els.length; i < len; i++) {
11013             el.dom = els[i];
11014                 Roo.Element.prototype[fn].apply(el, args);
11015         }
11016         return this;
11017     },
11018     /**
11019      * Returns a flyweight Element of the dom element object at the specified index
11020      * @param {Number} index
11021      * @return {Roo.Element}
11022      */
11023     item : function(index){
11024         if(!this.elements[index]){
11025             return null;
11026         }
11027         this.el.dom = this.elements[index];
11028         return this.el;
11029     },
11030
11031     // fixes scope with flyweight
11032     addListener : function(eventName, handler, scope, opt){
11033         var els = this.elements;
11034         for(var i = 0, len = els.length; i < len; i++) {
11035             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11036         }
11037         return this;
11038     },
11039
11040     /**
11041     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11042     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11043     * a reference to the dom node, use el.dom.</b>
11044     * @param {Function} fn The function to call
11045     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11046     * @return {CompositeElement} this
11047     */
11048     each : function(fn, scope){
11049         var els = this.elements;
11050         var el = this.el;
11051         for(var i = 0, len = els.length; i < len; i++){
11052             el.dom = els[i];
11053                 if(fn.call(scope || el, el, this, i) === false){
11054                 break;
11055             }
11056         }
11057         return this;
11058     },
11059
11060     indexOf : function(el){
11061         return this.elements.indexOf(Roo.getDom(el));
11062     },
11063
11064     replaceElement : function(el, replacement, domReplace){
11065         var index = typeof el == 'number' ? el : this.indexOf(el);
11066         if(index !== -1){
11067             replacement = Roo.getDom(replacement);
11068             if(domReplace){
11069                 var d = this.elements[index];
11070                 d.parentNode.insertBefore(replacement, d);
11071                 d.parentNode.removeChild(d);
11072             }
11073             this.elements.splice(index, 1, replacement);
11074         }
11075         return this;
11076     }
11077 });
11078 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11079
11080 /*
11081  * Based on:
11082  * Ext JS Library 1.1.1
11083  * Copyright(c) 2006-2007, Ext JS, LLC.
11084  *
11085  * Originally Released Under LGPL - original licence link has changed is not relivant.
11086  *
11087  * Fork - LGPL
11088  * <script type="text/javascript">
11089  */
11090
11091  
11092
11093 /**
11094  * @class Roo.data.Connection
11095  * @extends Roo.util.Observable
11096  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11097  * either to a configured URL, or to a URL specified at request time.<br><br>
11098  * <p>
11099  * Requests made by this class are asynchronous, and will return immediately. No data from
11100  * the server will be available to the statement immediately following the {@link #request} call.
11101  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11102  * <p>
11103  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11104  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11105  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11106  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11107  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11108  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11109  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11110  * standard DOM methods.
11111  * @constructor
11112  * @param {Object} config a configuration object.
11113  */
11114 Roo.data.Connection = function(config){
11115     Roo.apply(this, config);
11116     this.addEvents({
11117         /**
11118          * @event beforerequest
11119          * Fires before a network request is made to retrieve a data object.
11120          * @param {Connection} conn This Connection object.
11121          * @param {Object} options The options config object passed to the {@link #request} method.
11122          */
11123         "beforerequest" : true,
11124         /**
11125          * @event requestcomplete
11126          * Fires if the request was successfully completed.
11127          * @param {Connection} conn This Connection object.
11128          * @param {Object} response The XHR object containing the response data.
11129          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11130          * @param {Object} options The options config object passed to the {@link #request} method.
11131          */
11132         "requestcomplete" : true,
11133         /**
11134          * @event requestexception
11135          * Fires if an error HTTP status was returned from the server.
11136          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11137          * @param {Connection} conn This Connection object.
11138          * @param {Object} response The XHR object containing the response data.
11139          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11140          * @param {Object} options The options config object passed to the {@link #request} method.
11141          */
11142         "requestexception" : true
11143     });
11144     Roo.data.Connection.superclass.constructor.call(this);
11145 };
11146
11147 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11148     /**
11149      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11150      */
11151     /**
11152      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11153      * extra parameters to each request made by this object. (defaults to undefined)
11154      */
11155     /**
11156      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11157      *  to each request made by this object. (defaults to undefined)
11158      */
11159     /**
11160      * @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)
11161      */
11162     /**
11163      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11164      */
11165     timeout : 30000,
11166     /**
11167      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11168      * @type Boolean
11169      */
11170     autoAbort:false,
11171
11172     /**
11173      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11174      * @type Boolean
11175      */
11176     disableCaching: true,
11177
11178     /**
11179      * Sends an HTTP request to a remote server.
11180      * @param {Object} options An object which may contain the following properties:<ul>
11181      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11182      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11183      * request, a url encoded string or a function to call to get either.</li>
11184      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11185      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11186      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11187      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11188      * <li>options {Object} The parameter to the request call.</li>
11189      * <li>success {Boolean} True if the request succeeded.</li>
11190      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11191      * </ul></li>
11192      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11193      * The callback is passed the following parameters:<ul>
11194      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11195      * <li>options {Object} The parameter to the request call.</li>
11196      * </ul></li>
11197      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11198      * The callback is passed the following parameters:<ul>
11199      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11200      * <li>options {Object} The parameter to the request call.</li>
11201      * </ul></li>
11202      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11203      * for the callback function. Defaults to the browser window.</li>
11204      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11205      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11206      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11207      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11208      * params for the post data. Any params will be appended to the URL.</li>
11209      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11210      * </ul>
11211      * @return {Number} transactionId
11212      */
11213     request : function(o){
11214         if(this.fireEvent("beforerequest", this, o) !== false){
11215             var p = o.params;
11216
11217             if(typeof p == "function"){
11218                 p = p.call(o.scope||window, o);
11219             }
11220             if(typeof p == "object"){
11221                 p = Roo.urlEncode(o.params);
11222             }
11223             if(this.extraParams){
11224                 var extras = Roo.urlEncode(this.extraParams);
11225                 p = p ? (p + '&' + extras) : extras;
11226             }
11227
11228             var url = o.url || this.url;
11229             if(typeof url == 'function'){
11230                 url = url.call(o.scope||window, o);
11231             }
11232
11233             if(o.form){
11234                 var form = Roo.getDom(o.form);
11235                 url = url || form.action;
11236
11237                 var enctype = form.getAttribute("enctype");
11238                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11239                     return this.doFormUpload(o, p, url);
11240                 }
11241                 var f = Roo.lib.Ajax.serializeForm(form);
11242                 p = p ? (p + '&' + f) : f;
11243             }
11244
11245             var hs = o.headers;
11246             if(this.defaultHeaders){
11247                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11248                 if(!o.headers){
11249                     o.headers = hs;
11250                 }
11251             }
11252
11253             var cb = {
11254                 success: this.handleResponse,
11255                 failure: this.handleFailure,
11256                 scope: this,
11257                 argument: {options: o},
11258                 timeout : this.timeout
11259             };
11260
11261             var method = o.method||this.method||(p ? "POST" : "GET");
11262
11263             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11264                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11265             }
11266
11267             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11268                 if(o.autoAbort){
11269                     this.abort();
11270                 }
11271             }else if(this.autoAbort !== false){
11272                 this.abort();
11273             }
11274
11275             if((method == 'GET' && p) || o.xmlData){
11276                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11277                 p = '';
11278             }
11279             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11280             return this.transId;
11281         }else{
11282             Roo.callback(o.callback, o.scope, [o, null, null]);
11283             return null;
11284         }
11285     },
11286
11287     /**
11288      * Determine whether this object has a request outstanding.
11289      * @param {Number} transactionId (Optional) defaults to the last transaction
11290      * @return {Boolean} True if there is an outstanding request.
11291      */
11292     isLoading : function(transId){
11293         if(transId){
11294             return Roo.lib.Ajax.isCallInProgress(transId);
11295         }else{
11296             return this.transId ? true : false;
11297         }
11298     },
11299
11300     /**
11301      * Aborts any outstanding request.
11302      * @param {Number} transactionId (Optional) defaults to the last transaction
11303      */
11304     abort : function(transId){
11305         if(transId || this.isLoading()){
11306             Roo.lib.Ajax.abort(transId || this.transId);
11307         }
11308     },
11309
11310     // private
11311     handleResponse : function(response){
11312         this.transId = false;
11313         var options = response.argument.options;
11314         response.argument = options ? options.argument : null;
11315         this.fireEvent("requestcomplete", this, response, options);
11316         Roo.callback(options.success, options.scope, [response, options]);
11317         Roo.callback(options.callback, options.scope, [options, true, response]);
11318     },
11319
11320     // private
11321     handleFailure : function(response, e){
11322         this.transId = false;
11323         var options = response.argument.options;
11324         response.argument = options ? options.argument : null;
11325         this.fireEvent("requestexception", this, response, options, e);
11326         Roo.callback(options.failure, options.scope, [response, options]);
11327         Roo.callback(options.callback, options.scope, [options, false, response]);
11328     },
11329
11330     // private
11331     doFormUpload : function(o, ps, url){
11332         var id = Roo.id();
11333         var frame = document.createElement('iframe');
11334         frame.id = id;
11335         frame.name = id;
11336         frame.className = 'x-hidden';
11337         if(Roo.isIE){
11338             frame.src = Roo.SSL_SECURE_URL;
11339         }
11340         document.body.appendChild(frame);
11341
11342         if(Roo.isIE){
11343            document.frames[id].name = id;
11344         }
11345
11346         var form = Roo.getDom(o.form);
11347         form.target = id;
11348         form.method = 'POST';
11349         form.enctype = form.encoding = 'multipart/form-data';
11350         if(url){
11351             form.action = url;
11352         }
11353
11354         var hiddens, hd;
11355         if(ps){ // add dynamic params
11356             hiddens = [];
11357             ps = Roo.urlDecode(ps, false);
11358             for(var k in ps){
11359                 if(ps.hasOwnProperty(k)){
11360                     hd = document.createElement('input');
11361                     hd.type = 'hidden';
11362                     hd.name = k;
11363                     hd.value = ps[k];
11364                     form.appendChild(hd);
11365                     hiddens.push(hd);
11366                 }
11367             }
11368         }
11369
11370         function cb(){
11371             var r = {  // bogus response object
11372                 responseText : '',
11373                 responseXML : null
11374             };
11375
11376             r.argument = o ? o.argument : null;
11377
11378             try { //
11379                 var doc;
11380                 if(Roo.isIE){
11381                     doc = frame.contentWindow.document;
11382                 }else {
11383                     doc = (frame.contentDocument || window.frames[id].document);
11384                 }
11385                 if(doc && doc.body){
11386                     r.responseText = doc.body.innerHTML;
11387                 }
11388                 if(doc && doc.XMLDocument){
11389                     r.responseXML = doc.XMLDocument;
11390                 }else {
11391                     r.responseXML = doc;
11392                 }
11393             }
11394             catch(e) {
11395                 // ignore
11396             }
11397
11398             Roo.EventManager.removeListener(frame, 'load', cb, this);
11399
11400             this.fireEvent("requestcomplete", this, r, o);
11401             Roo.callback(o.success, o.scope, [r, o]);
11402             Roo.callback(o.callback, o.scope, [o, true, r]);
11403
11404             setTimeout(function(){document.body.removeChild(frame);}, 100);
11405         }
11406
11407         Roo.EventManager.on(frame, 'load', cb, this);
11408         form.submit();
11409
11410         if(hiddens){ // remove dynamic params
11411             for(var i = 0, len = hiddens.length; i < len; i++){
11412                 form.removeChild(hiddens[i]);
11413             }
11414         }
11415     }
11416 });
11417
11418 /**
11419  * @class Roo.Ajax
11420  * @extends Roo.data.Connection
11421  * Global Ajax request class.
11422  *
11423  * @singleton
11424  */
11425 Roo.Ajax = new Roo.data.Connection({
11426     // fix up the docs
11427    /**
11428      * @cfg {String} url @hide
11429      */
11430     /**
11431      * @cfg {Object} extraParams @hide
11432      */
11433     /**
11434      * @cfg {Object} defaultHeaders @hide
11435      */
11436     /**
11437      * @cfg {String} method (Optional) @hide
11438      */
11439     /**
11440      * @cfg {Number} timeout (Optional) @hide
11441      */
11442     /**
11443      * @cfg {Boolean} autoAbort (Optional) @hide
11444      */
11445
11446     /**
11447      * @cfg {Boolean} disableCaching (Optional) @hide
11448      */
11449
11450     /**
11451      * @property  disableCaching
11452      * True to add a unique cache-buster param to GET requests. (defaults to true)
11453      * @type Boolean
11454      */
11455     /**
11456      * @property  url
11457      * The default URL to be used for requests to the server. (defaults to undefined)
11458      * @type String
11459      */
11460     /**
11461      * @property  extraParams
11462      * An object containing properties which are used as
11463      * extra parameters to each request made by this object. (defaults to undefined)
11464      * @type Object
11465      */
11466     /**
11467      * @property  defaultHeaders
11468      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11469      * @type Object
11470      */
11471     /**
11472      * @property  method
11473      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11474      * @type String
11475      */
11476     /**
11477      * @property  timeout
11478      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11479      * @type Number
11480      */
11481
11482     /**
11483      * @property  autoAbort
11484      * Whether a new request should abort any pending requests. (defaults to false)
11485      * @type Boolean
11486      */
11487     autoAbort : false,
11488
11489     /**
11490      * Serialize the passed form into a url encoded string
11491      * @param {String/HTMLElement} form
11492      * @return {String}
11493      */
11494     serializeForm : function(form){
11495         return Roo.lib.Ajax.serializeForm(form);
11496     }
11497 });/*
11498  * Based on:
11499  * Ext JS Library 1.1.1
11500  * Copyright(c) 2006-2007, Ext JS, LLC.
11501  *
11502  * Originally Released Under LGPL - original licence link has changed is not relivant.
11503  *
11504  * Fork - LGPL
11505  * <script type="text/javascript">
11506  */
11507  
11508 /**
11509  * @class Roo.Ajax
11510  * @extends Roo.data.Connection
11511  * Global Ajax request class.
11512  *
11513  * @instanceOf  Roo.data.Connection
11514  */
11515 Roo.Ajax = new Roo.data.Connection({
11516     // fix up the docs
11517     
11518     /**
11519      * fix up scoping
11520      * @scope Roo.Ajax
11521      */
11522     
11523    /**
11524      * @cfg {String} url @hide
11525      */
11526     /**
11527      * @cfg {Object} extraParams @hide
11528      */
11529     /**
11530      * @cfg {Object} defaultHeaders @hide
11531      */
11532     /**
11533      * @cfg {String} method (Optional) @hide
11534      */
11535     /**
11536      * @cfg {Number} timeout (Optional) @hide
11537      */
11538     /**
11539      * @cfg {Boolean} autoAbort (Optional) @hide
11540      */
11541
11542     /**
11543      * @cfg {Boolean} disableCaching (Optional) @hide
11544      */
11545
11546     /**
11547      * @property  disableCaching
11548      * True to add a unique cache-buster param to GET requests. (defaults to true)
11549      * @type Boolean
11550      */
11551     /**
11552      * @property  url
11553      * The default URL to be used for requests to the server. (defaults to undefined)
11554      * @type String
11555      */
11556     /**
11557      * @property  extraParams
11558      * An object containing properties which are used as
11559      * extra parameters to each request made by this object. (defaults to undefined)
11560      * @type Object
11561      */
11562     /**
11563      * @property  defaultHeaders
11564      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11565      * @type Object
11566      */
11567     /**
11568      * @property  method
11569      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11570      * @type String
11571      */
11572     /**
11573      * @property  timeout
11574      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11575      * @type Number
11576      */
11577
11578     /**
11579      * @property  autoAbort
11580      * Whether a new request should abort any pending requests. (defaults to false)
11581      * @type Boolean
11582      */
11583     autoAbort : false,
11584
11585     /**
11586      * Serialize the passed form into a url encoded string
11587      * @param {String/HTMLElement} form
11588      * @return {String}
11589      */
11590     serializeForm : function(form){
11591         return Roo.lib.Ajax.serializeForm(form);
11592     }
11593 });/*
11594  * Based on:
11595  * Ext JS Library 1.1.1
11596  * Copyright(c) 2006-2007, Ext JS, LLC.
11597  *
11598  * Originally Released Under LGPL - original licence link has changed is not relivant.
11599  *
11600  * Fork - LGPL
11601  * <script type="text/javascript">
11602  */
11603
11604  
11605 /**
11606  * @class Roo.UpdateManager
11607  * @extends Roo.util.Observable
11608  * Provides AJAX-style update for Element object.<br><br>
11609  * Usage:<br>
11610  * <pre><code>
11611  * // Get it from a Roo.Element object
11612  * var el = Roo.get("foo");
11613  * var mgr = el.getUpdateManager();
11614  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11615  * ...
11616  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11617  * <br>
11618  * // or directly (returns the same UpdateManager instance)
11619  * var mgr = new Roo.UpdateManager("myElementId");
11620  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11621  * mgr.on("update", myFcnNeedsToKnow);
11622  * <br>
11623    // short handed call directly from the element object
11624    Roo.get("foo").load({
11625         url: "bar.php",
11626         scripts:true,
11627         params: "for=bar",
11628         text: "Loading Foo..."
11629    });
11630  * </code></pre>
11631  * @constructor
11632  * Create new UpdateManager directly.
11633  * @param {String/HTMLElement/Roo.Element} el The element to update
11634  * @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).
11635  */
11636 Roo.UpdateManager = function(el, forceNew){
11637     el = Roo.get(el);
11638     if(!forceNew && el.updateManager){
11639         return el.updateManager;
11640     }
11641     /**
11642      * The Element object
11643      * @type Roo.Element
11644      */
11645     this.el = el;
11646     /**
11647      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11648      * @type String
11649      */
11650     this.defaultUrl = null;
11651
11652     this.addEvents({
11653         /**
11654          * @event beforeupdate
11655          * Fired before an update is made, return false from your handler and the update is cancelled.
11656          * @param {Roo.Element} el
11657          * @param {String/Object/Function} url
11658          * @param {String/Object} params
11659          */
11660         "beforeupdate": true,
11661         /**
11662          * @event update
11663          * Fired after successful update is made.
11664          * @param {Roo.Element} el
11665          * @param {Object} oResponseObject The response Object
11666          */
11667         "update": true,
11668         /**
11669          * @event failure
11670          * Fired on update failure.
11671          * @param {Roo.Element} el
11672          * @param {Object} oResponseObject The response Object
11673          */
11674         "failure": true
11675     });
11676     var d = Roo.UpdateManager.defaults;
11677     /**
11678      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11679      * @type String
11680      */
11681     this.sslBlankUrl = d.sslBlankUrl;
11682     /**
11683      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11684      * @type Boolean
11685      */
11686     this.disableCaching = d.disableCaching;
11687     /**
11688      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11689      * @type String
11690      */
11691     this.indicatorText = d.indicatorText;
11692     /**
11693      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11694      * @type String
11695      */
11696     this.showLoadIndicator = d.showLoadIndicator;
11697     /**
11698      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11699      * @type Number
11700      */
11701     this.timeout = d.timeout;
11702
11703     /**
11704      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11705      * @type Boolean
11706      */
11707     this.loadScripts = d.loadScripts;
11708
11709     /**
11710      * Transaction object of current executing transaction
11711      */
11712     this.transaction = null;
11713
11714     /**
11715      * @private
11716      */
11717     this.autoRefreshProcId = null;
11718     /**
11719      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11720      * @type Function
11721      */
11722     this.refreshDelegate = this.refresh.createDelegate(this);
11723     /**
11724      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11725      * @type Function
11726      */
11727     this.updateDelegate = this.update.createDelegate(this);
11728     /**
11729      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11730      * @type Function
11731      */
11732     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11733     /**
11734      * @private
11735      */
11736     this.successDelegate = this.processSuccess.createDelegate(this);
11737     /**
11738      * @private
11739      */
11740     this.failureDelegate = this.processFailure.createDelegate(this);
11741
11742     if(!this.renderer){
11743      /**
11744       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11745       */
11746     this.renderer = new Roo.UpdateManager.BasicRenderer();
11747     }
11748     
11749     Roo.UpdateManager.superclass.constructor.call(this);
11750 };
11751
11752 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11753     /**
11754      * Get the Element this UpdateManager is bound to
11755      * @return {Roo.Element} The element
11756      */
11757     getEl : function(){
11758         return this.el;
11759     },
11760     /**
11761      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11762      * @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:
11763 <pre><code>
11764 um.update({<br/>
11765     url: "your-url.php",<br/>
11766     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11767     callback: yourFunction,<br/>
11768     scope: yourObject, //(optional scope)  <br/>
11769     discardUrl: false, <br/>
11770     nocache: false,<br/>
11771     text: "Loading...",<br/>
11772     timeout: 30,<br/>
11773     scripts: false<br/>
11774 });
11775 </code></pre>
11776      * The only required property is url. The optional properties nocache, text and scripts
11777      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11778      * @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}
11779      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11780      * @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.
11781      */
11782     update : function(url, params, callback, discardUrl){
11783         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11784             var method = this.method, cfg;
11785             if(typeof url == "object"){ // must be config object
11786                 cfg = url;
11787                 url = cfg.url;
11788                 params = params || cfg.params;
11789                 callback = callback || cfg.callback;
11790                 discardUrl = discardUrl || cfg.discardUrl;
11791                 if(callback && cfg.scope){
11792                     callback = callback.createDelegate(cfg.scope);
11793                 }
11794                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11795                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11796                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11797                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11798                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11799             }
11800             this.showLoading();
11801             if(!discardUrl){
11802                 this.defaultUrl = url;
11803             }
11804             if(typeof url == "function"){
11805                 url = url.call(this);
11806             }
11807
11808             method = method || (params ? "POST" : "GET");
11809             if(method == "GET"){
11810                 url = this.prepareUrl(url);
11811             }
11812
11813             var o = Roo.apply(cfg ||{}, {
11814                 url : url,
11815                 params: params,
11816                 success: this.successDelegate,
11817                 failure: this.failureDelegate,
11818                 callback: undefined,
11819                 timeout: (this.timeout*1000),
11820                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11821             });
11822
11823             this.transaction = Roo.Ajax.request(o);
11824         }
11825     },
11826
11827     /**
11828      * 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.
11829      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11830      * @param {String/HTMLElement} form The form Id or form element
11831      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11832      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11833      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11834      */
11835     formUpdate : function(form, url, reset, callback){
11836         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11837             if(typeof url == "function"){
11838                 url = url.call(this);
11839             }
11840             form = Roo.getDom(form);
11841             this.transaction = Roo.Ajax.request({
11842                 form: form,
11843                 url:url,
11844                 success: this.successDelegate,
11845                 failure: this.failureDelegate,
11846                 timeout: (this.timeout*1000),
11847                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11848             });
11849             this.showLoading.defer(1, this);
11850         }
11851     },
11852
11853     /**
11854      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11855      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11856      */
11857     refresh : function(callback){
11858         if(this.defaultUrl == null){
11859             return;
11860         }
11861         this.update(this.defaultUrl, null, callback, true);
11862     },
11863
11864     /**
11865      * Set this element to auto refresh.
11866      * @param {Number} interval How often to update (in seconds).
11867      * @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)
11868      * @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}
11869      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11870      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11871      */
11872     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11873         if(refreshNow){
11874             this.update(url || this.defaultUrl, params, callback, true);
11875         }
11876         if(this.autoRefreshProcId){
11877             clearInterval(this.autoRefreshProcId);
11878         }
11879         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11880     },
11881
11882     /**
11883      * Stop auto refresh on this element.
11884      */
11885      stopAutoRefresh : function(){
11886         if(this.autoRefreshProcId){
11887             clearInterval(this.autoRefreshProcId);
11888             delete this.autoRefreshProcId;
11889         }
11890     },
11891
11892     isAutoRefreshing : function(){
11893        return this.autoRefreshProcId ? true : false;
11894     },
11895     /**
11896      * Called to update the element to "Loading" state. Override to perform custom action.
11897      */
11898     showLoading : function(){
11899         if(this.showLoadIndicator){
11900             this.el.update(this.indicatorText);
11901         }
11902     },
11903
11904     /**
11905      * Adds unique parameter to query string if disableCaching = true
11906      * @private
11907      */
11908     prepareUrl : function(url){
11909         if(this.disableCaching){
11910             var append = "_dc=" + (new Date().getTime());
11911             if(url.indexOf("?") !== -1){
11912                 url += "&" + append;
11913             }else{
11914                 url += "?" + append;
11915             }
11916         }
11917         return url;
11918     },
11919
11920     /**
11921      * @private
11922      */
11923     processSuccess : function(response){
11924         this.transaction = null;
11925         if(response.argument.form && response.argument.reset){
11926             try{ // put in try/catch since some older FF releases had problems with this
11927                 response.argument.form.reset();
11928             }catch(e){}
11929         }
11930         if(this.loadScripts){
11931             this.renderer.render(this.el, response, this,
11932                 this.updateComplete.createDelegate(this, [response]));
11933         }else{
11934             this.renderer.render(this.el, response, this);
11935             this.updateComplete(response);
11936         }
11937     },
11938
11939     updateComplete : function(response){
11940         this.fireEvent("update", this.el, response);
11941         if(typeof response.argument.callback == "function"){
11942             response.argument.callback(this.el, true, response);
11943         }
11944     },
11945
11946     /**
11947      * @private
11948      */
11949     processFailure : function(response){
11950         this.transaction = null;
11951         this.fireEvent("failure", this.el, response);
11952         if(typeof response.argument.callback == "function"){
11953             response.argument.callback(this.el, false, response);
11954         }
11955     },
11956
11957     /**
11958      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11959      * @param {Object} renderer The object implementing the render() method
11960      */
11961     setRenderer : function(renderer){
11962         this.renderer = renderer;
11963     },
11964
11965     getRenderer : function(){
11966        return this.renderer;
11967     },
11968
11969     /**
11970      * Set the defaultUrl used for updates
11971      * @param {String/Function} defaultUrl The url or a function to call to get the url
11972      */
11973     setDefaultUrl : function(defaultUrl){
11974         this.defaultUrl = defaultUrl;
11975     },
11976
11977     /**
11978      * Aborts the executing transaction
11979      */
11980     abort : function(){
11981         if(this.transaction){
11982             Roo.Ajax.abort(this.transaction);
11983         }
11984     },
11985
11986     /**
11987      * Returns true if an update is in progress
11988      * @return {Boolean}
11989      */
11990     isUpdating : function(){
11991         if(this.transaction){
11992             return Roo.Ajax.isLoading(this.transaction);
11993         }
11994         return false;
11995     }
11996 });
11997
11998 /**
11999  * @class Roo.UpdateManager.defaults
12000  * @static (not really - but it helps the doc tool)
12001  * The defaults collection enables customizing the default properties of UpdateManager
12002  */
12003    Roo.UpdateManager.defaults = {
12004        /**
12005          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12006          * @type Number
12007          */
12008          timeout : 30,
12009
12010          /**
12011          * True to process scripts by default (Defaults to false).
12012          * @type Boolean
12013          */
12014         loadScripts : false,
12015
12016         /**
12017         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12018         * @type String
12019         */
12020         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12021         /**
12022          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12023          * @type Boolean
12024          */
12025         disableCaching : false,
12026         /**
12027          * Whether to show indicatorText when loading (Defaults to true).
12028          * @type Boolean
12029          */
12030         showLoadIndicator : true,
12031         /**
12032          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12033          * @type String
12034          */
12035         indicatorText : '<div class="loading-indicator">Loading...</div>'
12036    };
12037
12038 /**
12039  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12040  *Usage:
12041  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12042  * @param {String/HTMLElement/Roo.Element} el The element to update
12043  * @param {String} url The url
12044  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12045  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12046  * @static
12047  * @deprecated
12048  * @member Roo.UpdateManager
12049  */
12050 Roo.UpdateManager.updateElement = function(el, url, params, options){
12051     var um = Roo.get(el, true).getUpdateManager();
12052     Roo.apply(um, options);
12053     um.update(url, params, options ? options.callback : null);
12054 };
12055 // alias for backwards compat
12056 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12057 /**
12058  * @class Roo.UpdateManager.BasicRenderer
12059  * Default Content renderer. Updates the elements innerHTML with the responseText.
12060  */
12061 Roo.UpdateManager.BasicRenderer = function(){};
12062
12063 Roo.UpdateManager.BasicRenderer.prototype = {
12064     /**
12065      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12066      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12067      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12068      * @param {Roo.Element} el The element being rendered
12069      * @param {Object} response The YUI Connect response object
12070      * @param {UpdateManager} updateManager The calling update manager
12071      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12072      */
12073      render : function(el, response, updateManager, callback){
12074         el.update(response.responseText, updateManager.loadScripts, callback);
12075     }
12076 };
12077 /*
12078  * Based on:
12079  * Ext JS Library 1.1.1
12080  * Copyright(c) 2006-2007, Ext JS, LLC.
12081  *
12082  * Originally Released Under LGPL - original licence link has changed is not relivant.
12083  *
12084  * Fork - LGPL
12085  * <script type="text/javascript">
12086  */
12087
12088 /**
12089  * @class Roo.util.DelayedTask
12090  * Provides a convenient method of performing setTimeout where a new
12091  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12092  * You can use this class to buffer
12093  * the keypress events for a certain number of milliseconds, and perform only if they stop
12094  * for that amount of time.
12095  * @constructor The parameters to this constructor serve as defaults and are not required.
12096  * @param {Function} fn (optional) The default function to timeout
12097  * @param {Object} scope (optional) The default scope of that timeout
12098  * @param {Array} args (optional) The default Array of arguments
12099  */
12100 Roo.util.DelayedTask = function(fn, scope, args){
12101     var id = null, d, t;
12102
12103     var call = function(){
12104         var now = new Date().getTime();
12105         if(now - t >= d){
12106             clearInterval(id);
12107             id = null;
12108             fn.apply(scope, args || []);
12109         }
12110     };
12111     /**
12112      * Cancels any pending timeout and queues a new one
12113      * @param {Number} delay The milliseconds to delay
12114      * @param {Function} newFn (optional) Overrides function passed to constructor
12115      * @param {Object} newScope (optional) Overrides scope passed to constructor
12116      * @param {Array} newArgs (optional) Overrides args passed to constructor
12117      */
12118     this.delay = function(delay, newFn, newScope, newArgs){
12119         if(id && delay != d){
12120             this.cancel();
12121         }
12122         d = delay;
12123         t = new Date().getTime();
12124         fn = newFn || fn;
12125         scope = newScope || scope;
12126         args = newArgs || args;
12127         if(!id){
12128             id = setInterval(call, d);
12129         }
12130     };
12131
12132     /**
12133      * Cancel the last queued timeout
12134      */
12135     this.cancel = function(){
12136         if(id){
12137             clearInterval(id);
12138             id = null;
12139         }
12140     };
12141 };/*
12142  * Based on:
12143  * Ext JS Library 1.1.1
12144  * Copyright(c) 2006-2007, Ext JS, LLC.
12145  *
12146  * Originally Released Under LGPL - original licence link has changed is not relivant.
12147  *
12148  * Fork - LGPL
12149  * <script type="text/javascript">
12150  */
12151  
12152  
12153 Roo.util.TaskRunner = function(interval){
12154     interval = interval || 10;
12155     var tasks = [], removeQueue = [];
12156     var id = 0;
12157     var running = false;
12158
12159     var stopThread = function(){
12160         running = false;
12161         clearInterval(id);
12162         id = 0;
12163     };
12164
12165     var startThread = function(){
12166         if(!running){
12167             running = true;
12168             id = setInterval(runTasks, interval);
12169         }
12170     };
12171
12172     var removeTask = function(task){
12173         removeQueue.push(task);
12174         if(task.onStop){
12175             task.onStop();
12176         }
12177     };
12178
12179     var runTasks = function(){
12180         if(removeQueue.length > 0){
12181             for(var i = 0, len = removeQueue.length; i < len; i++){
12182                 tasks.remove(removeQueue[i]);
12183             }
12184             removeQueue = [];
12185             if(tasks.length < 1){
12186                 stopThread();
12187                 return;
12188             }
12189         }
12190         var now = new Date().getTime();
12191         for(var i = 0, len = tasks.length; i < len; ++i){
12192             var t = tasks[i];
12193             var itime = now - t.taskRunTime;
12194             if(t.interval <= itime){
12195                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12196                 t.taskRunTime = now;
12197                 if(rt === false || t.taskRunCount === t.repeat){
12198                     removeTask(t);
12199                     return;
12200                 }
12201             }
12202             if(t.duration && t.duration <= (now - t.taskStartTime)){
12203                 removeTask(t);
12204             }
12205         }
12206     };
12207
12208     /**
12209      * Queues a new task.
12210      * @param {Object} task
12211      */
12212     this.start = function(task){
12213         tasks.push(task);
12214         task.taskStartTime = new Date().getTime();
12215         task.taskRunTime = 0;
12216         task.taskRunCount = 0;
12217         startThread();
12218         return task;
12219     };
12220
12221     this.stop = function(task){
12222         removeTask(task);
12223         return task;
12224     };
12225
12226     this.stopAll = function(){
12227         stopThread();
12228         for(var i = 0, len = tasks.length; i < len; i++){
12229             if(tasks[i].onStop){
12230                 tasks[i].onStop();
12231             }
12232         }
12233         tasks = [];
12234         removeQueue = [];
12235     };
12236 };
12237
12238 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12239  * Based on:
12240  * Ext JS Library 1.1.1
12241  * Copyright(c) 2006-2007, Ext JS, LLC.
12242  *
12243  * Originally Released Under LGPL - original licence link has changed is not relivant.
12244  *
12245  * Fork - LGPL
12246  * <script type="text/javascript">
12247  */
12248
12249  
12250 /**
12251  * @class Roo.util.MixedCollection
12252  * @extends Roo.util.Observable
12253  * A Collection class that maintains both numeric indexes and keys and exposes events.
12254  * @constructor
12255  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12256  * collection (defaults to false)
12257  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12258  * and return the key value for that item.  This is used when available to look up the key on items that
12259  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12260  * equivalent to providing an implementation for the {@link #getKey} method.
12261  */
12262 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12263     this.items = [];
12264     this.map = {};
12265     this.keys = [];
12266     this.length = 0;
12267     this.addEvents({
12268         /**
12269          * @event clear
12270          * Fires when the collection is cleared.
12271          */
12272         "clear" : true,
12273         /**
12274          * @event add
12275          * Fires when an item is added to the collection.
12276          * @param {Number} index The index at which the item was added.
12277          * @param {Object} o The item added.
12278          * @param {String} key The key associated with the added item.
12279          */
12280         "add" : true,
12281         /**
12282          * @event replace
12283          * Fires when an item is replaced in the collection.
12284          * @param {String} key he key associated with the new added.
12285          * @param {Object} old The item being replaced.
12286          * @param {Object} new The new item.
12287          */
12288         "replace" : true,
12289         /**
12290          * @event remove
12291          * Fires when an item is removed from the collection.
12292          * @param {Object} o The item being removed.
12293          * @param {String} key (optional) The key associated with the removed item.
12294          */
12295         "remove" : true,
12296         "sort" : true
12297     });
12298     this.allowFunctions = allowFunctions === true;
12299     if(keyFn){
12300         this.getKey = keyFn;
12301     }
12302     Roo.util.MixedCollection.superclass.constructor.call(this);
12303 };
12304
12305 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12306     allowFunctions : false,
12307     
12308 /**
12309  * Adds an item to the collection.
12310  * @param {String} key The key to associate with the item
12311  * @param {Object} o The item to add.
12312  * @return {Object} The item added.
12313  */
12314     add : function(key, o){
12315         if(arguments.length == 1){
12316             o = arguments[0];
12317             key = this.getKey(o);
12318         }
12319         if(typeof key == "undefined" || key === null){
12320             this.length++;
12321             this.items.push(o);
12322             this.keys.push(null);
12323         }else{
12324             var old = this.map[key];
12325             if(old){
12326                 return this.replace(key, o);
12327             }
12328             this.length++;
12329             this.items.push(o);
12330             this.map[key] = o;
12331             this.keys.push(key);
12332         }
12333         this.fireEvent("add", this.length-1, o, key);
12334         return o;
12335     },
12336        
12337 /**
12338   * MixedCollection has a generic way to fetch keys if you implement getKey.
12339 <pre><code>
12340 // normal way
12341 var mc = new Roo.util.MixedCollection();
12342 mc.add(someEl.dom.id, someEl);
12343 mc.add(otherEl.dom.id, otherEl);
12344 //and so on
12345
12346 // using getKey
12347 var mc = new Roo.util.MixedCollection();
12348 mc.getKey = function(el){
12349    return el.dom.id;
12350 };
12351 mc.add(someEl);
12352 mc.add(otherEl);
12353
12354 // or via the constructor
12355 var mc = new Roo.util.MixedCollection(false, function(el){
12356    return el.dom.id;
12357 });
12358 mc.add(someEl);
12359 mc.add(otherEl);
12360 </code></pre>
12361  * @param o {Object} The item for which to find the key.
12362  * @return {Object} The key for the passed item.
12363  */
12364     getKey : function(o){
12365          return o.id; 
12366     },
12367    
12368 /**
12369  * Replaces an item in the collection.
12370  * @param {String} key The key associated with the item to replace, or the item to replace.
12371  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12372  * @return {Object}  The new item.
12373  */
12374     replace : function(key, o){
12375         if(arguments.length == 1){
12376             o = arguments[0];
12377             key = this.getKey(o);
12378         }
12379         var old = this.item(key);
12380         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12381              return this.add(key, o);
12382         }
12383         var index = this.indexOfKey(key);
12384         this.items[index] = o;
12385         this.map[key] = o;
12386         this.fireEvent("replace", key, old, o);
12387         return o;
12388     },
12389    
12390 /**
12391  * Adds all elements of an Array or an Object to the collection.
12392  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12393  * an Array of values, each of which are added to the collection.
12394  */
12395     addAll : function(objs){
12396         if(arguments.length > 1 || objs instanceof Array){
12397             var args = arguments.length > 1 ? arguments : objs;
12398             for(var i = 0, len = args.length; i < len; i++){
12399                 this.add(args[i]);
12400             }
12401         }else{
12402             for(var key in objs){
12403                 if(this.allowFunctions || typeof objs[key] != "function"){
12404                     this.add(key, objs[key]);
12405                 }
12406             }
12407         }
12408     },
12409    
12410 /**
12411  * Executes the specified function once for every item in the collection, passing each
12412  * item as the first and only parameter. returning false from the function will stop the iteration.
12413  * @param {Function} fn The function to execute for each item.
12414  * @param {Object} scope (optional) The scope in which to execute the function.
12415  */
12416     each : function(fn, scope){
12417         var items = [].concat(this.items); // each safe for removal
12418         for(var i = 0, len = items.length; i < len; i++){
12419             if(fn.call(scope || items[i], items[i], i, len) === false){
12420                 break;
12421             }
12422         }
12423     },
12424    
12425 /**
12426  * Executes the specified function once for every key in the collection, passing each
12427  * key, and its associated item as the first two parameters.
12428  * @param {Function} fn The function to execute for each item.
12429  * @param {Object} scope (optional) The scope in which to execute the function.
12430  */
12431     eachKey : function(fn, scope){
12432         for(var i = 0, len = this.keys.length; i < len; i++){
12433             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12434         }
12435     },
12436    
12437 /**
12438  * Returns the first item in the collection which elicits a true return value from the
12439  * passed selection function.
12440  * @param {Function} fn The selection function to execute for each item.
12441  * @param {Object} scope (optional) The scope in which to execute the function.
12442  * @return {Object} The first item in the collection which returned true from the selection function.
12443  */
12444     find : function(fn, scope){
12445         for(var i = 0, len = this.items.length; i < len; i++){
12446             if(fn.call(scope || window, this.items[i], this.keys[i])){
12447                 return this.items[i];
12448             }
12449         }
12450         return null;
12451     },
12452    
12453 /**
12454  * Inserts an item at the specified index in the collection.
12455  * @param {Number} index The index to insert the item at.
12456  * @param {String} key The key to associate with the new item, or the item itself.
12457  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12458  * @return {Object} The item inserted.
12459  */
12460     insert : function(index, key, o){
12461         if(arguments.length == 2){
12462             o = arguments[1];
12463             key = this.getKey(o);
12464         }
12465         if(index >= this.length){
12466             return this.add(key, o);
12467         }
12468         this.length++;
12469         this.items.splice(index, 0, o);
12470         if(typeof key != "undefined" && key != null){
12471             this.map[key] = o;
12472         }
12473         this.keys.splice(index, 0, key);
12474         this.fireEvent("add", index, o, key);
12475         return o;
12476     },
12477    
12478 /**
12479  * Removed an item from the collection.
12480  * @param {Object} o The item to remove.
12481  * @return {Object} The item removed.
12482  */
12483     remove : function(o){
12484         return this.removeAt(this.indexOf(o));
12485     },
12486    
12487 /**
12488  * Remove an item from a specified index in the collection.
12489  * @param {Number} index The index within the collection of the item to remove.
12490  */
12491     removeAt : function(index){
12492         if(index < this.length && index >= 0){
12493             this.length--;
12494             var o = this.items[index];
12495             this.items.splice(index, 1);
12496             var key = this.keys[index];
12497             if(typeof key != "undefined"){
12498                 delete this.map[key];
12499             }
12500             this.keys.splice(index, 1);
12501             this.fireEvent("remove", o, key);
12502         }
12503     },
12504    
12505 /**
12506  * Removed an item associated with the passed key fom the collection.
12507  * @param {String} key The key of the item to remove.
12508  */
12509     removeKey : function(key){
12510         return this.removeAt(this.indexOfKey(key));
12511     },
12512    
12513 /**
12514  * Returns the number of items in the collection.
12515  * @return {Number} the number of items in the collection.
12516  */
12517     getCount : function(){
12518         return this.length; 
12519     },
12520    
12521 /**
12522  * Returns index within the collection of the passed Object.
12523  * @param {Object} o The item to find the index of.
12524  * @return {Number} index of the item.
12525  */
12526     indexOf : function(o){
12527         if(!this.items.indexOf){
12528             for(var i = 0, len = this.items.length; i < len; i++){
12529                 if(this.items[i] == o) return i;
12530             }
12531             return -1;
12532         }else{
12533             return this.items.indexOf(o);
12534         }
12535     },
12536    
12537 /**
12538  * Returns index within the collection of the passed key.
12539  * @param {String} key The key to find the index of.
12540  * @return {Number} index of the key.
12541  */
12542     indexOfKey : function(key){
12543         if(!this.keys.indexOf){
12544             for(var i = 0, len = this.keys.length; i < len; i++){
12545                 if(this.keys[i] == key) return i;
12546             }
12547             return -1;
12548         }else{
12549             return this.keys.indexOf(key);
12550         }
12551     },
12552    
12553 /**
12554  * Returns the item associated with the passed key OR index. Key has priority over index.
12555  * @param {String/Number} key The key or index of the item.
12556  * @return {Object} The item associated with the passed key.
12557  */
12558     item : function(key){
12559         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12560         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12561     },
12562     
12563 /**
12564  * Returns the item at the specified index.
12565  * @param {Number} index The index of the item.
12566  * @return {Object}
12567  */
12568     itemAt : function(index){
12569         return this.items[index];
12570     },
12571     
12572 /**
12573  * Returns the item associated with the passed key.
12574  * @param {String/Number} key The key of the item.
12575  * @return {Object} The item associated with the passed key.
12576  */
12577     key : function(key){
12578         return this.map[key];
12579     },
12580    
12581 /**
12582  * Returns true if the collection contains the passed Object as an item.
12583  * @param {Object} o  The Object to look for in the collection.
12584  * @return {Boolean} True if the collection contains the Object as an item.
12585  */
12586     contains : function(o){
12587         return this.indexOf(o) != -1;
12588     },
12589    
12590 /**
12591  * Returns true if the collection contains the passed Object as a key.
12592  * @param {String} key The key to look for in the collection.
12593  * @return {Boolean} True if the collection contains the Object as a key.
12594  */
12595     containsKey : function(key){
12596         return typeof this.map[key] != "undefined";
12597     },
12598    
12599 /**
12600  * Removes all items from the collection.
12601  */
12602     clear : function(){
12603         this.length = 0;
12604         this.items = [];
12605         this.keys = [];
12606         this.map = {};
12607         this.fireEvent("clear");
12608     },
12609    
12610 /**
12611  * Returns the first item in the collection.
12612  * @return {Object} the first item in the collection..
12613  */
12614     first : function(){
12615         return this.items[0]; 
12616     },
12617    
12618 /**
12619  * Returns the last item in the collection.
12620  * @return {Object} the last item in the collection..
12621  */
12622     last : function(){
12623         return this.items[this.length-1];   
12624     },
12625     
12626     _sort : function(property, dir, fn){
12627         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12628         fn = fn || function(a, b){
12629             return a-b;
12630         };
12631         var c = [], k = this.keys, items = this.items;
12632         for(var i = 0, len = items.length; i < len; i++){
12633             c[c.length] = {key: k[i], value: items[i], index: i};
12634         }
12635         c.sort(function(a, b){
12636             var v = fn(a[property], b[property]) * dsc;
12637             if(v == 0){
12638                 v = (a.index < b.index ? -1 : 1);
12639             }
12640             return v;
12641         });
12642         for(var i = 0, len = c.length; i < len; i++){
12643             items[i] = c[i].value;
12644             k[i] = c[i].key;
12645         }
12646         this.fireEvent("sort", this);
12647     },
12648     
12649     /**
12650      * Sorts this collection with the passed comparison function
12651      * @param {String} direction (optional) "ASC" or "DESC"
12652      * @param {Function} fn (optional) comparison function
12653      */
12654     sort : function(dir, fn){
12655         this._sort("value", dir, fn);
12656     },
12657     
12658     /**
12659      * Sorts this collection by keys
12660      * @param {String} direction (optional) "ASC" or "DESC"
12661      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12662      */
12663     keySort : function(dir, fn){
12664         this._sort("key", dir, fn || function(a, b){
12665             return String(a).toUpperCase()-String(b).toUpperCase();
12666         });
12667     },
12668     
12669     /**
12670      * Returns a range of items in this collection
12671      * @param {Number} startIndex (optional) defaults to 0
12672      * @param {Number} endIndex (optional) default to the last item
12673      * @return {Array} An array of items
12674      */
12675     getRange : function(start, end){
12676         var items = this.items;
12677         if(items.length < 1){
12678             return [];
12679         }
12680         start = start || 0;
12681         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12682         var r = [];
12683         if(start <= end){
12684             for(var i = start; i <= end; i++) {
12685                     r[r.length] = items[i];
12686             }
12687         }else{
12688             for(var i = start; i >= end; i--) {
12689                     r[r.length] = items[i];
12690             }
12691         }
12692         return r;
12693     },
12694         
12695     /**
12696      * Filter the <i>objects</i> in this collection by a specific property. 
12697      * Returns a new collection that has been filtered.
12698      * @param {String} property A property on your objects
12699      * @param {String/RegExp} value Either string that the property values 
12700      * should start with or a RegExp to test against the property
12701      * @return {MixedCollection} The new filtered collection
12702      */
12703     filter : function(property, value){
12704         if(!value.exec){ // not a regex
12705             value = String(value);
12706             if(value.length == 0){
12707                 return this.clone();
12708             }
12709             value = new RegExp("^" + Roo.escapeRe(value), "i");
12710         }
12711         return this.filterBy(function(o){
12712             return o && value.test(o[property]);
12713         });
12714         },
12715     
12716     /**
12717      * Filter by a function. * Returns a new collection that has been filtered.
12718      * The passed function will be called with each 
12719      * object in the collection. If the function returns true, the value is included 
12720      * otherwise it is filtered.
12721      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12722      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12723      * @return {MixedCollection} The new filtered collection
12724      */
12725     filterBy : function(fn, scope){
12726         var r = new Roo.util.MixedCollection();
12727         r.getKey = this.getKey;
12728         var k = this.keys, it = this.items;
12729         for(var i = 0, len = it.length; i < len; i++){
12730             if(fn.call(scope||this, it[i], k[i])){
12731                                 r.add(k[i], it[i]);
12732                         }
12733         }
12734         return r;
12735     },
12736     
12737     /**
12738      * Creates a duplicate of this collection
12739      * @return {MixedCollection}
12740      */
12741     clone : function(){
12742         var r = new Roo.util.MixedCollection();
12743         var k = this.keys, it = this.items;
12744         for(var i = 0, len = it.length; i < len; i++){
12745             r.add(k[i], it[i]);
12746         }
12747         r.getKey = this.getKey;
12748         return r;
12749     }
12750 });
12751 /**
12752  * Returns the item associated with the passed key or index.
12753  * @method
12754  * @param {String/Number} key The key or index of the item.
12755  * @return {Object} The item associated with the passed key.
12756  */
12757 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12758  * Based on:
12759  * Ext JS Library 1.1.1
12760  * Copyright(c) 2006-2007, Ext JS, LLC.
12761  *
12762  * Originally Released Under LGPL - original licence link has changed is not relivant.
12763  *
12764  * Fork - LGPL
12765  * <script type="text/javascript">
12766  */
12767 /**
12768  * @class Roo.util.JSON
12769  * Modified version of Douglas Crockford"s json.js that doesn"t
12770  * mess with the Object prototype 
12771  * http://www.json.org/js.html
12772  * @singleton
12773  */
12774 Roo.util.JSON = new (function(){
12775     var useHasOwn = {}.hasOwnProperty ? true : false;
12776     
12777     // crashes Safari in some instances
12778     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12779     
12780     var pad = function(n) {
12781         return n < 10 ? "0" + n : n;
12782     };
12783     
12784     var m = {
12785         "\b": '\\b',
12786         "\t": '\\t',
12787         "\n": '\\n',
12788         "\f": '\\f',
12789         "\r": '\\r',
12790         '"' : '\\"',
12791         "\\": '\\\\'
12792     };
12793
12794     var encodeString = function(s){
12795         if (/["\\\x00-\x1f]/.test(s)) {
12796             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12797                 var c = m[b];
12798                 if(c){
12799                     return c;
12800                 }
12801                 c = b.charCodeAt();
12802                 return "\\u00" +
12803                     Math.floor(c / 16).toString(16) +
12804                     (c % 16).toString(16);
12805             }) + '"';
12806         }
12807         return '"' + s + '"';
12808     };
12809     
12810     var encodeArray = function(o){
12811         var a = ["["], b, i, l = o.length, v;
12812             for (i = 0; i < l; i += 1) {
12813                 v = o[i];
12814                 switch (typeof v) {
12815                     case "undefined":
12816                     case "function":
12817                     case "unknown":
12818                         break;
12819                     default:
12820                         if (b) {
12821                             a.push(',');
12822                         }
12823                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12824                         b = true;
12825                 }
12826             }
12827             a.push("]");
12828             return a.join("");
12829     };
12830     
12831     var encodeDate = function(o){
12832         return '"' + o.getFullYear() + "-" +
12833                 pad(o.getMonth() + 1) + "-" +
12834                 pad(o.getDate()) + "T" +
12835                 pad(o.getHours()) + ":" +
12836                 pad(o.getMinutes()) + ":" +
12837                 pad(o.getSeconds()) + '"';
12838     };
12839     
12840     /**
12841      * Encodes an Object, Array or other value
12842      * @param {Mixed} o The variable to encode
12843      * @return {String} The JSON string
12844      */
12845     this.encode = function(o)
12846     {
12847         // should this be extended to fully wrap stringify..
12848         
12849         if(typeof o == "undefined" || o === null){
12850             return "null";
12851         }else if(o instanceof Array){
12852             return encodeArray(o);
12853         }else if(o instanceof Date){
12854             return encodeDate(o);
12855         }else if(typeof o == "string"){
12856             return encodeString(o);
12857         }else if(typeof o == "number"){
12858             return isFinite(o) ? String(o) : "null";
12859         }else if(typeof o == "boolean"){
12860             return String(o);
12861         }else {
12862             var a = ["{"], b, i, v;
12863             for (i in o) {
12864                 if(!useHasOwn || o.hasOwnProperty(i)) {
12865                     v = o[i];
12866                     switch (typeof v) {
12867                     case "undefined":
12868                     case "function":
12869                     case "unknown":
12870                         break;
12871                     default:
12872                         if(b){
12873                             a.push(',');
12874                         }
12875                         a.push(this.encode(i), ":",
12876                                 v === null ? "null" : this.encode(v));
12877                         b = true;
12878                     }
12879                 }
12880             }
12881             a.push("}");
12882             return a.join("");
12883         }
12884     };
12885     
12886     /**
12887      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12888      * @param {String} json The JSON string
12889      * @return {Object} The resulting object
12890      */
12891     this.decode = function(json){
12892         
12893         return  /** eval:var:json */ eval("(" + json + ')');
12894     };
12895 })();
12896 /** 
12897  * Shorthand for {@link Roo.util.JSON#encode}
12898  * @member Roo encode 
12899  * @method */
12900 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12901 /** 
12902  * Shorthand for {@link Roo.util.JSON#decode}
12903  * @member Roo decode 
12904  * @method */
12905 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12906 /*
12907  * Based on:
12908  * Ext JS Library 1.1.1
12909  * Copyright(c) 2006-2007, Ext JS, LLC.
12910  *
12911  * Originally Released Under LGPL - original licence link has changed is not relivant.
12912  *
12913  * Fork - LGPL
12914  * <script type="text/javascript">
12915  */
12916  
12917 /**
12918  * @class Roo.util.Format
12919  * Reusable data formatting functions
12920  * @singleton
12921  */
12922 Roo.util.Format = function(){
12923     var trimRe = /^\s+|\s+$/g;
12924     return {
12925         /**
12926          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12927          * @param {String} value The string to truncate
12928          * @param {Number} length The maximum length to allow before truncating
12929          * @return {String} The converted text
12930          */
12931         ellipsis : function(value, len){
12932             if(value && value.length > len){
12933                 return value.substr(0, len-3)+"...";
12934             }
12935             return value;
12936         },
12937
12938         /**
12939          * Checks a reference and converts it to empty string if it is undefined
12940          * @param {Mixed} value Reference to check
12941          * @return {Mixed} Empty string if converted, otherwise the original value
12942          */
12943         undef : function(value){
12944             return typeof value != "undefined" ? value : "";
12945         },
12946
12947         /**
12948          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12949          * @param {String} value The string to encode
12950          * @return {String} The encoded text
12951          */
12952         htmlEncode : function(value){
12953             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12954         },
12955
12956         /**
12957          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12958          * @param {String} value The string to decode
12959          * @return {String} The decoded text
12960          */
12961         htmlDecode : function(value){
12962             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12963         },
12964
12965         /**
12966          * Trims any whitespace from either side of a string
12967          * @param {String} value The text to trim
12968          * @return {String} The trimmed text
12969          */
12970         trim : function(value){
12971             return String(value).replace(trimRe, "");
12972         },
12973
12974         /**
12975          * Returns a substring from within an original string
12976          * @param {String} value The original text
12977          * @param {Number} start The start index of the substring
12978          * @param {Number} length The length of the substring
12979          * @return {String} The substring
12980          */
12981         substr : function(value, start, length){
12982             return String(value).substr(start, length);
12983         },
12984
12985         /**
12986          * Converts a string to all lower case letters
12987          * @param {String} value The text to convert
12988          * @return {String} The converted text
12989          */
12990         lowercase : function(value){
12991             return String(value).toLowerCase();
12992         },
12993
12994         /**
12995          * Converts a string to all upper case letters
12996          * @param {String} value The text to convert
12997          * @return {String} The converted text
12998          */
12999         uppercase : function(value){
13000             return String(value).toUpperCase();
13001         },
13002
13003         /**
13004          * Converts the first character only of a string to upper case
13005          * @param {String} value The text to convert
13006          * @return {String} The converted text
13007          */
13008         capitalize : function(value){
13009             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13010         },
13011
13012         // private
13013         call : function(value, fn){
13014             if(arguments.length > 2){
13015                 var args = Array.prototype.slice.call(arguments, 2);
13016                 args.unshift(value);
13017                  
13018                 return /** eval:var:value */  eval(fn).apply(window, args);
13019             }else{
13020                 /** eval:var:value */
13021                 return /** eval:var:value */ eval(fn).call(window, value);
13022             }
13023         },
13024
13025        
13026         /**
13027          * safer version of Math.toFixed..??/
13028          * @param {Number/String} value The numeric value to format
13029          * @param {Number/String} value Decimal places 
13030          * @return {String} The formatted currency string
13031          */
13032         toFixed : function(v, n)
13033         {
13034             // why not use to fixed - precision is buggered???
13035             if (!n) {
13036                 return Math.round(v-0);
13037             }
13038             var fact = Math.pow(10,n+1);
13039             v = (Math.round((v-0)*fact))/fact;
13040             var z = (''+fact).substring(2);
13041             if (v == Math.floor(v)) {
13042                 return Math.floor(v) + '.' + z;
13043             }
13044             
13045             // now just padd decimals..
13046             var ps = String(v).split('.');
13047             var fd = (ps[1] + z);
13048             var r = fd.substring(0,n); 
13049             var rm = fd.substring(n); 
13050             if (rm < 5) {
13051                 return ps[0] + '.' + r;
13052             }
13053             r*=1; // turn it into a number;
13054             r++;
13055             if (String(r).length != n) {
13056                 ps[0]*=1;
13057                 ps[0]++;
13058                 r = String(r).substring(1); // chop the end off.
13059             }
13060             
13061             return ps[0] + '.' + r;
13062              
13063         },
13064         
13065         /**
13066          * Format a number as US currency
13067          * @param {Number/String} value The numeric value to format
13068          * @return {String} The formatted currency string
13069          */
13070         usMoney : function(v){
13071             v = (Math.round((v-0)*100))/100;
13072             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13073             v = String(v);
13074             var ps = v.split('.');
13075             var whole = ps[0];
13076             var sub = ps[1] ? '.'+ ps[1] : '.00';
13077             var r = /(\d+)(\d{3})/;
13078             while (r.test(whole)) {
13079                 whole = whole.replace(r, '$1' + ',' + '$2');
13080             }
13081             return "$" + whole + sub ;
13082         },
13083         
13084         /**
13085          * Parse a value into a formatted date using the specified format pattern.
13086          * @param {Mixed} value The value to format
13087          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13088          * @return {String} The formatted date string
13089          */
13090         date : function(v, format){
13091             if(!v){
13092                 return "";
13093             }
13094             if(!(v instanceof Date)){
13095                 v = new Date(Date.parse(v));
13096             }
13097             return v.dateFormat(format || "m/d/Y");
13098         },
13099
13100         /**
13101          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13102          * @param {String} format Any valid date format string
13103          * @return {Function} The date formatting function
13104          */
13105         dateRenderer : function(format){
13106             return function(v){
13107                 return Roo.util.Format.date(v, format);  
13108             };
13109         },
13110
13111         // private
13112         stripTagsRE : /<\/?[^>]+>/gi,
13113         
13114         /**
13115          * Strips all HTML tags
13116          * @param {Mixed} value The text from which to strip tags
13117          * @return {String} The stripped text
13118          */
13119         stripTags : function(v){
13120             return !v ? v : String(v).replace(this.stripTagsRE, "");
13121         }
13122     };
13123 }();/*
13124  * Based on:
13125  * Ext JS Library 1.1.1
13126  * Copyright(c) 2006-2007, Ext JS, LLC.
13127  *
13128  * Originally Released Under LGPL - original licence link has changed is not relivant.
13129  *
13130  * Fork - LGPL
13131  * <script type="text/javascript">
13132  */
13133
13134
13135  
13136
13137 /**
13138  * @class Roo.MasterTemplate
13139  * @extends Roo.Template
13140  * Provides a template that can have child templates. The syntax is:
13141 <pre><code>
13142 var t = new Roo.MasterTemplate(
13143         '&lt;select name="{name}"&gt;',
13144                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13145         '&lt;/select&gt;'
13146 );
13147 t.add('options', {value: 'foo', text: 'bar'});
13148 // or you can add multiple child elements in one shot
13149 t.addAll('options', [
13150     {value: 'foo', text: 'bar'},
13151     {value: 'foo2', text: 'bar2'},
13152     {value: 'foo3', text: 'bar3'}
13153 ]);
13154 // then append, applying the master template values
13155 t.append('my-form', {name: 'my-select'});
13156 </code></pre>
13157 * A name attribute for the child template is not required if you have only one child
13158 * template or you want to refer to them by index.
13159  */
13160 Roo.MasterTemplate = function(){
13161     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13162     this.originalHtml = this.html;
13163     var st = {};
13164     var m, re = this.subTemplateRe;
13165     re.lastIndex = 0;
13166     var subIndex = 0;
13167     while(m = re.exec(this.html)){
13168         var name = m[1], content = m[2];
13169         st[subIndex] = {
13170             name: name,
13171             index: subIndex,
13172             buffer: [],
13173             tpl : new Roo.Template(content)
13174         };
13175         if(name){
13176             st[name] = st[subIndex];
13177         }
13178         st[subIndex].tpl.compile();
13179         st[subIndex].tpl.call = this.call.createDelegate(this);
13180         subIndex++;
13181     }
13182     this.subCount = subIndex;
13183     this.subs = st;
13184 };
13185 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13186     /**
13187     * The regular expression used to match sub templates
13188     * @type RegExp
13189     * @property
13190     */
13191     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13192
13193     /**
13194      * Applies the passed values to a child template.
13195      * @param {String/Number} name (optional) The name or index of the child template
13196      * @param {Array/Object} values The values to be applied to the template
13197      * @return {MasterTemplate} this
13198      */
13199      add : function(name, values){
13200         if(arguments.length == 1){
13201             values = arguments[0];
13202             name = 0;
13203         }
13204         var s = this.subs[name];
13205         s.buffer[s.buffer.length] = s.tpl.apply(values);
13206         return this;
13207     },
13208
13209     /**
13210      * Applies all the passed values to a child template.
13211      * @param {String/Number} name (optional) The name or index of the child template
13212      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13213      * @param {Boolean} reset (optional) True to reset the template first
13214      * @return {MasterTemplate} this
13215      */
13216     fill : function(name, values, reset){
13217         var a = arguments;
13218         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13219             values = a[0];
13220             name = 0;
13221             reset = a[1];
13222         }
13223         if(reset){
13224             this.reset();
13225         }
13226         for(var i = 0, len = values.length; i < len; i++){
13227             this.add(name, values[i]);
13228         }
13229         return this;
13230     },
13231
13232     /**
13233      * Resets the template for reuse
13234      * @return {MasterTemplate} this
13235      */
13236      reset : function(){
13237         var s = this.subs;
13238         for(var i = 0; i < this.subCount; i++){
13239             s[i].buffer = [];
13240         }
13241         return this;
13242     },
13243
13244     applyTemplate : function(values){
13245         var s = this.subs;
13246         var replaceIndex = -1;
13247         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13248             return s[++replaceIndex].buffer.join("");
13249         });
13250         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13251     },
13252
13253     apply : function(){
13254         return this.applyTemplate.apply(this, arguments);
13255     },
13256
13257     compile : function(){return this;}
13258 });
13259
13260 /**
13261  * Alias for fill().
13262  * @method
13263  */
13264 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13265  /**
13266  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13267  * var tpl = Roo.MasterTemplate.from('element-id');
13268  * @param {String/HTMLElement} el
13269  * @param {Object} config
13270  * @static
13271  */
13272 Roo.MasterTemplate.from = function(el, config){
13273     el = Roo.getDom(el);
13274     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13275 };/*
13276  * Based on:
13277  * Ext JS Library 1.1.1
13278  * Copyright(c) 2006-2007, Ext JS, LLC.
13279  *
13280  * Originally Released Under LGPL - original licence link has changed is not relivant.
13281  *
13282  * Fork - LGPL
13283  * <script type="text/javascript">
13284  */
13285
13286  
13287 /**
13288  * @class Roo.util.CSS
13289  * Utility class for manipulating CSS rules
13290  * @singleton
13291  */
13292 Roo.util.CSS = function(){
13293         var rules = null;
13294         var doc = document;
13295
13296     var camelRe = /(-[a-z])/gi;
13297     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13298
13299    return {
13300    /**
13301     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13302     * tag and appended to the HEAD of the document.
13303     * @param {String|Object} cssText The text containing the css rules
13304     * @param {String} id An id to add to the stylesheet for later removal
13305     * @return {StyleSheet}
13306     */
13307     createStyleSheet : function(cssText, id){
13308         var ss;
13309         var head = doc.getElementsByTagName("head")[0];
13310         var nrules = doc.createElement("style");
13311         nrules.setAttribute("type", "text/css");
13312         if(id){
13313             nrules.setAttribute("id", id);
13314         }
13315         if (typeof(cssText) != 'string') {
13316             // support object maps..
13317             // not sure if this a good idea.. 
13318             // perhaps it should be merged with the general css handling
13319             // and handle js style props.
13320             var cssTextNew = [];
13321             for(var n in cssText) {
13322                 var citems = [];
13323                 for(var k in cssText[n]) {
13324                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13325                 }
13326                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13327                 
13328             }
13329             cssText = cssTextNew.join("\n");
13330             
13331         }
13332        
13333        
13334        if(Roo.isIE){
13335            head.appendChild(nrules);
13336            ss = nrules.styleSheet;
13337            ss.cssText = cssText;
13338        }else{
13339            try{
13340                 nrules.appendChild(doc.createTextNode(cssText));
13341            }catch(e){
13342                nrules.cssText = cssText; 
13343            }
13344            head.appendChild(nrules);
13345            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13346        }
13347        this.cacheStyleSheet(ss);
13348        return ss;
13349    },
13350
13351    /**
13352     * Removes a style or link tag by id
13353     * @param {String} id The id of the tag
13354     */
13355    removeStyleSheet : function(id){
13356        var existing = doc.getElementById(id);
13357        if(existing){
13358            existing.parentNode.removeChild(existing);
13359        }
13360    },
13361
13362    /**
13363     * Dynamically swaps an existing stylesheet reference for a new one
13364     * @param {String} id The id of an existing link tag to remove
13365     * @param {String} url The href of the new stylesheet to include
13366     */
13367    swapStyleSheet : function(id, url){
13368        this.removeStyleSheet(id);
13369        var ss = doc.createElement("link");
13370        ss.setAttribute("rel", "stylesheet");
13371        ss.setAttribute("type", "text/css");
13372        ss.setAttribute("id", id);
13373        ss.setAttribute("href", url);
13374        doc.getElementsByTagName("head")[0].appendChild(ss);
13375    },
13376    
13377    /**
13378     * Refresh the rule cache if you have dynamically added stylesheets
13379     * @return {Object} An object (hash) of rules indexed by selector
13380     */
13381    refreshCache : function(){
13382        return this.getRules(true);
13383    },
13384
13385    // private
13386    cacheStyleSheet : function(stylesheet){
13387        if(!rules){
13388            rules = {};
13389        }
13390        try{// try catch for cross domain access issue
13391            var ssRules = stylesheet.cssRules || stylesheet.rules;
13392            for(var j = ssRules.length-1; j >= 0; --j){
13393                rules[ssRules[j].selectorText] = ssRules[j];
13394            }
13395        }catch(e){}
13396    },
13397    
13398    /**
13399     * Gets all css rules for the document
13400     * @param {Boolean} refreshCache true to refresh the internal cache
13401     * @return {Object} An object (hash) of rules indexed by selector
13402     */
13403    getRules : function(refreshCache){
13404                 if(rules == null || refreshCache){
13405                         rules = {};
13406                         var ds = doc.styleSheets;
13407                         for(var i =0, len = ds.length; i < len; i++){
13408                             try{
13409                         this.cacheStyleSheet(ds[i]);
13410                     }catch(e){} 
13411                 }
13412                 }
13413                 return rules;
13414         },
13415         
13416         /**
13417     * Gets an an individual CSS rule by selector(s)
13418     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13419     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13420     * @return {CSSRule} The CSS rule or null if one is not found
13421     */
13422    getRule : function(selector, refreshCache){
13423                 var rs = this.getRules(refreshCache);
13424                 if(!(selector instanceof Array)){
13425                     return rs[selector];
13426                 }
13427                 for(var i = 0; i < selector.length; i++){
13428                         if(rs[selector[i]]){
13429                                 return rs[selector[i]];
13430                         }
13431                 }
13432                 return null;
13433         },
13434         
13435         
13436         /**
13437     * Updates a rule property
13438     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13439     * @param {String} property The css property
13440     * @param {String} value The new value for the property
13441     * @return {Boolean} true If a rule was found and updated
13442     */
13443    updateRule : function(selector, property, value){
13444                 if(!(selector instanceof Array)){
13445                         var rule = this.getRule(selector);
13446                         if(rule){
13447                                 rule.style[property.replace(camelRe, camelFn)] = value;
13448                                 return true;
13449                         }
13450                 }else{
13451                         for(var i = 0; i < selector.length; i++){
13452                                 if(this.updateRule(selector[i], property, value)){
13453                                         return true;
13454                                 }
13455                         }
13456                 }
13457                 return false;
13458         }
13459    };   
13460 }();/*
13461  * Based on:
13462  * Ext JS Library 1.1.1
13463  * Copyright(c) 2006-2007, Ext JS, LLC.
13464  *
13465  * Originally Released Under LGPL - original licence link has changed is not relivant.
13466  *
13467  * Fork - LGPL
13468  * <script type="text/javascript">
13469  */
13470
13471  
13472
13473 /**
13474  * @class Roo.util.ClickRepeater
13475  * @extends Roo.util.Observable
13476  * 
13477  * A wrapper class which can be applied to any element. Fires a "click" event while the
13478  * mouse is pressed. The interval between firings may be specified in the config but
13479  * defaults to 10 milliseconds.
13480  * 
13481  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13482  * 
13483  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13484  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13485  * Similar to an autorepeat key delay.
13486  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13487  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13488  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13489  *           "interval" and "delay" are ignored. "immediate" is honored.
13490  * @cfg {Boolean} preventDefault True to prevent the default click event
13491  * @cfg {Boolean} stopDefault True to stop the default click event
13492  * 
13493  * @history
13494  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13495  *     2007-02-02 jvs Renamed to ClickRepeater
13496  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13497  *
13498  *  @constructor
13499  * @param {String/HTMLElement/Element} el The element to listen on
13500  * @param {Object} config
13501  **/
13502 Roo.util.ClickRepeater = function(el, config)
13503 {
13504     this.el = Roo.get(el);
13505     this.el.unselectable();
13506
13507     Roo.apply(this, config);
13508
13509     this.addEvents({
13510     /**
13511      * @event mousedown
13512      * Fires when the mouse button is depressed.
13513      * @param {Roo.util.ClickRepeater} this
13514      */
13515         "mousedown" : true,
13516     /**
13517      * @event click
13518      * Fires on a specified interval during the time the element is pressed.
13519      * @param {Roo.util.ClickRepeater} this
13520      */
13521         "click" : true,
13522     /**
13523      * @event mouseup
13524      * Fires when the mouse key is released.
13525      * @param {Roo.util.ClickRepeater} this
13526      */
13527         "mouseup" : true
13528     });
13529
13530     this.el.on("mousedown", this.handleMouseDown, this);
13531     if(this.preventDefault || this.stopDefault){
13532         this.el.on("click", function(e){
13533             if(this.preventDefault){
13534                 e.preventDefault();
13535             }
13536             if(this.stopDefault){
13537                 e.stopEvent();
13538             }
13539         }, this);
13540     }
13541
13542     // allow inline handler
13543     if(this.handler){
13544         this.on("click", this.handler,  this.scope || this);
13545     }
13546
13547     Roo.util.ClickRepeater.superclass.constructor.call(this);
13548 };
13549
13550 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13551     interval : 20,
13552     delay: 250,
13553     preventDefault : true,
13554     stopDefault : false,
13555     timer : 0,
13556
13557     // private
13558     handleMouseDown : function(){
13559         clearTimeout(this.timer);
13560         this.el.blur();
13561         if(this.pressClass){
13562             this.el.addClass(this.pressClass);
13563         }
13564         this.mousedownTime = new Date();
13565
13566         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13567         this.el.on("mouseout", this.handleMouseOut, this);
13568
13569         this.fireEvent("mousedown", this);
13570         this.fireEvent("click", this);
13571         
13572         this.timer = this.click.defer(this.delay || this.interval, this);
13573     },
13574
13575     // private
13576     click : function(){
13577         this.fireEvent("click", this);
13578         this.timer = this.click.defer(this.getInterval(), this);
13579     },
13580
13581     // private
13582     getInterval: function(){
13583         if(!this.accelerate){
13584             return this.interval;
13585         }
13586         var pressTime = this.mousedownTime.getElapsed();
13587         if(pressTime < 500){
13588             return 400;
13589         }else if(pressTime < 1700){
13590             return 320;
13591         }else if(pressTime < 2600){
13592             return 250;
13593         }else if(pressTime < 3500){
13594             return 180;
13595         }else if(pressTime < 4400){
13596             return 140;
13597         }else if(pressTime < 5300){
13598             return 80;
13599         }else if(pressTime < 6200){
13600             return 50;
13601         }else{
13602             return 10;
13603         }
13604     },
13605
13606     // private
13607     handleMouseOut : function(){
13608         clearTimeout(this.timer);
13609         if(this.pressClass){
13610             this.el.removeClass(this.pressClass);
13611         }
13612         this.el.on("mouseover", this.handleMouseReturn, this);
13613     },
13614
13615     // private
13616     handleMouseReturn : function(){
13617         this.el.un("mouseover", this.handleMouseReturn);
13618         if(this.pressClass){
13619             this.el.addClass(this.pressClass);
13620         }
13621         this.click();
13622     },
13623
13624     // private
13625     handleMouseUp : function(){
13626         clearTimeout(this.timer);
13627         this.el.un("mouseover", this.handleMouseReturn);
13628         this.el.un("mouseout", this.handleMouseOut);
13629         Roo.get(document).un("mouseup", this.handleMouseUp);
13630         this.el.removeClass(this.pressClass);
13631         this.fireEvent("mouseup", this);
13632     }
13633 });/*
13634  * Based on:
13635  * Ext JS Library 1.1.1
13636  * Copyright(c) 2006-2007, Ext JS, LLC.
13637  *
13638  * Originally Released Under LGPL - original licence link has changed is not relivant.
13639  *
13640  * Fork - LGPL
13641  * <script type="text/javascript">
13642  */
13643
13644  
13645 /**
13646  * @class Roo.KeyNav
13647  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13648  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13649  * way to implement custom navigation schemes for any UI component.</p>
13650  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13651  * pageUp, pageDown, del, home, end.  Usage:</p>
13652  <pre><code>
13653 var nav = new Roo.KeyNav("my-element", {
13654     "left" : function(e){
13655         this.moveLeft(e.ctrlKey);
13656     },
13657     "right" : function(e){
13658         this.moveRight(e.ctrlKey);
13659     },
13660     "enter" : function(e){
13661         this.save();
13662     },
13663     scope : this
13664 });
13665 </code></pre>
13666  * @constructor
13667  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13668  * @param {Object} config The config
13669  */
13670 Roo.KeyNav = function(el, config){
13671     this.el = Roo.get(el);
13672     Roo.apply(this, config);
13673     if(!this.disabled){
13674         this.disabled = true;
13675         this.enable();
13676     }
13677 };
13678
13679 Roo.KeyNav.prototype = {
13680     /**
13681      * @cfg {Boolean} disabled
13682      * True to disable this KeyNav instance (defaults to false)
13683      */
13684     disabled : false,
13685     /**
13686      * @cfg {String} defaultEventAction
13687      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13688      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13689      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13690      */
13691     defaultEventAction: "stopEvent",
13692     /**
13693      * @cfg {Boolean} forceKeyDown
13694      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13695      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13696      * handle keydown instead of keypress.
13697      */
13698     forceKeyDown : false,
13699
13700     // private
13701     prepareEvent : function(e){
13702         var k = e.getKey();
13703         var h = this.keyToHandler[k];
13704         //if(h && this[h]){
13705         //    e.stopPropagation();
13706         //}
13707         if(Roo.isSafari && h && k >= 37 && k <= 40){
13708             e.stopEvent();
13709         }
13710     },
13711
13712     // private
13713     relay : function(e){
13714         var k = e.getKey();
13715         var h = this.keyToHandler[k];
13716         if(h && this[h]){
13717             if(this.doRelay(e, this[h], h) !== true){
13718                 e[this.defaultEventAction]();
13719             }
13720         }
13721     },
13722
13723     // private
13724     doRelay : function(e, h, hname){
13725         return h.call(this.scope || this, e);
13726     },
13727
13728     // possible handlers
13729     enter : false,
13730     left : false,
13731     right : false,
13732     up : false,
13733     down : false,
13734     tab : false,
13735     esc : false,
13736     pageUp : false,
13737     pageDown : false,
13738     del : false,
13739     home : false,
13740     end : false,
13741
13742     // quick lookup hash
13743     keyToHandler : {
13744         37 : "left",
13745         39 : "right",
13746         38 : "up",
13747         40 : "down",
13748         33 : "pageUp",
13749         34 : "pageDown",
13750         46 : "del",
13751         36 : "home",
13752         35 : "end",
13753         13 : "enter",
13754         27 : "esc",
13755         9  : "tab"
13756     },
13757
13758         /**
13759          * Enable this KeyNav
13760          */
13761         enable: function(){
13762                 if(this.disabled){
13763             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13764             // the EventObject will normalize Safari automatically
13765             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13766                 this.el.on("keydown", this.relay,  this);
13767             }else{
13768                 this.el.on("keydown", this.prepareEvent,  this);
13769                 this.el.on("keypress", this.relay,  this);
13770             }
13771                     this.disabled = false;
13772                 }
13773         },
13774
13775         /**
13776          * Disable this KeyNav
13777          */
13778         disable: function(){
13779                 if(!this.disabled){
13780                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13781                 this.el.un("keydown", this.relay);
13782             }else{
13783                 this.el.un("keydown", this.prepareEvent);
13784                 this.el.un("keypress", this.relay);
13785             }
13786                     this.disabled = true;
13787                 }
13788         }
13789 };/*
13790  * Based on:
13791  * Ext JS Library 1.1.1
13792  * Copyright(c) 2006-2007, Ext JS, LLC.
13793  *
13794  * Originally Released Under LGPL - original licence link has changed is not relivant.
13795  *
13796  * Fork - LGPL
13797  * <script type="text/javascript">
13798  */
13799
13800  
13801 /**
13802  * @class Roo.KeyMap
13803  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13804  * The constructor accepts the same config object as defined by {@link #addBinding}.
13805  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13806  * combination it will call the function with this signature (if the match is a multi-key
13807  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13808  * A KeyMap can also handle a string representation of keys.<br />
13809  * Usage:
13810  <pre><code>
13811 // map one key by key code
13812 var map = new Roo.KeyMap("my-element", {
13813     key: 13, // or Roo.EventObject.ENTER
13814     fn: myHandler,
13815     scope: myObject
13816 });
13817
13818 // map multiple keys to one action by string
13819 var map = new Roo.KeyMap("my-element", {
13820     key: "a\r\n\t",
13821     fn: myHandler,
13822     scope: myObject
13823 });
13824
13825 // map multiple keys to multiple actions by strings and array of codes
13826 var map = new Roo.KeyMap("my-element", [
13827     {
13828         key: [10,13],
13829         fn: function(){ alert("Return was pressed"); }
13830     }, {
13831         key: "abc",
13832         fn: function(){ alert('a, b or c was pressed'); }
13833     }, {
13834         key: "\t",
13835         ctrl:true,
13836         shift:true,
13837         fn: function(){ alert('Control + shift + tab was pressed.'); }
13838     }
13839 ]);
13840 </code></pre>
13841  * <b>Note: A KeyMap starts enabled</b>
13842  * @constructor
13843  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13844  * @param {Object} config The config (see {@link #addBinding})
13845  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13846  */
13847 Roo.KeyMap = function(el, config, eventName){
13848     this.el  = Roo.get(el);
13849     this.eventName = eventName || "keydown";
13850     this.bindings = [];
13851     if(config){
13852         this.addBinding(config);
13853     }
13854     this.enable();
13855 };
13856
13857 Roo.KeyMap.prototype = {
13858     /**
13859      * True to stop the event from bubbling and prevent the default browser action if the
13860      * key was handled by the KeyMap (defaults to false)
13861      * @type Boolean
13862      */
13863     stopEvent : false,
13864
13865     /**
13866      * Add a new binding to this KeyMap. The following config object properties are supported:
13867      * <pre>
13868 Property    Type             Description
13869 ----------  ---------------  ----------------------------------------------------------------------
13870 key         String/Array     A single keycode or an array of keycodes to handle
13871 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13872 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13873 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13874 fn          Function         The function to call when KeyMap finds the expected key combination
13875 scope       Object           The scope of the callback function
13876 </pre>
13877      *
13878      * Usage:
13879      * <pre><code>
13880 // Create a KeyMap
13881 var map = new Roo.KeyMap(document, {
13882     key: Roo.EventObject.ENTER,
13883     fn: handleKey,
13884     scope: this
13885 });
13886
13887 //Add a new binding to the existing KeyMap later
13888 map.addBinding({
13889     key: 'abc',
13890     shift: true,
13891     fn: handleKey,
13892     scope: this
13893 });
13894 </code></pre>
13895      * @param {Object/Array} config A single KeyMap config or an array of configs
13896      */
13897         addBinding : function(config){
13898         if(config instanceof Array){
13899             for(var i = 0, len = config.length; i < len; i++){
13900                 this.addBinding(config[i]);
13901             }
13902             return;
13903         }
13904         var keyCode = config.key,
13905             shift = config.shift, 
13906             ctrl = config.ctrl, 
13907             alt = config.alt,
13908             fn = config.fn,
13909             scope = config.scope;
13910         if(typeof keyCode == "string"){
13911             var ks = [];
13912             var keyString = keyCode.toUpperCase();
13913             for(var j = 0, len = keyString.length; j < len; j++){
13914                 ks.push(keyString.charCodeAt(j));
13915             }
13916             keyCode = ks;
13917         }
13918         var keyArray = keyCode instanceof Array;
13919         var handler = function(e){
13920             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13921                 var k = e.getKey();
13922                 if(keyArray){
13923                     for(var i = 0, len = keyCode.length; i < len; i++){
13924                         if(keyCode[i] == k){
13925                           if(this.stopEvent){
13926                               e.stopEvent();
13927                           }
13928                           fn.call(scope || window, k, e);
13929                           return;
13930                         }
13931                     }
13932                 }else{
13933                     if(k == keyCode){
13934                         if(this.stopEvent){
13935                            e.stopEvent();
13936                         }
13937                         fn.call(scope || window, k, e);
13938                     }
13939                 }
13940             }
13941         };
13942         this.bindings.push(handler);  
13943         },
13944
13945     /**
13946      * Shorthand for adding a single key listener
13947      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13948      * following options:
13949      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13950      * @param {Function} fn The function to call
13951      * @param {Object} scope (optional) The scope of the function
13952      */
13953     on : function(key, fn, scope){
13954         var keyCode, shift, ctrl, alt;
13955         if(typeof key == "object" && !(key instanceof Array)){
13956             keyCode = key.key;
13957             shift = key.shift;
13958             ctrl = key.ctrl;
13959             alt = key.alt;
13960         }else{
13961             keyCode = key;
13962         }
13963         this.addBinding({
13964             key: keyCode,
13965             shift: shift,
13966             ctrl: ctrl,
13967             alt: alt,
13968             fn: fn,
13969             scope: scope
13970         })
13971     },
13972
13973     // private
13974     handleKeyDown : function(e){
13975             if(this.enabled){ //just in case
13976             var b = this.bindings;
13977             for(var i = 0, len = b.length; i < len; i++){
13978                 b[i].call(this, e);
13979             }
13980             }
13981         },
13982         
13983         /**
13984          * Returns true if this KeyMap is enabled
13985          * @return {Boolean} 
13986          */
13987         isEnabled : function(){
13988             return this.enabled;  
13989         },
13990         
13991         /**
13992          * Enables this KeyMap
13993          */
13994         enable: function(){
13995                 if(!this.enabled){
13996                     this.el.on(this.eventName, this.handleKeyDown, this);
13997                     this.enabled = true;
13998                 }
13999         },
14000
14001         /**
14002          * Disable this KeyMap
14003          */
14004         disable: function(){
14005                 if(this.enabled){
14006                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14007                     this.enabled = false;
14008                 }
14009         }
14010 };/*
14011  * Based on:
14012  * Ext JS Library 1.1.1
14013  * Copyright(c) 2006-2007, Ext JS, LLC.
14014  *
14015  * Originally Released Under LGPL - original licence link has changed is not relivant.
14016  *
14017  * Fork - LGPL
14018  * <script type="text/javascript">
14019  */
14020
14021  
14022 /**
14023  * @class Roo.util.TextMetrics
14024  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14025  * wide, in pixels, a given block of text will be.
14026  * @singleton
14027  */
14028 Roo.util.TextMetrics = function(){
14029     var shared;
14030     return {
14031         /**
14032          * Measures the size of the specified text
14033          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14034          * that can affect the size of the rendered text
14035          * @param {String} text The text to measure
14036          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14037          * in order to accurately measure the text height
14038          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14039          */
14040         measure : function(el, text, fixedWidth){
14041             if(!shared){
14042                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14043             }
14044             shared.bind(el);
14045             shared.setFixedWidth(fixedWidth || 'auto');
14046             return shared.getSize(text);
14047         },
14048
14049         /**
14050          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14051          * the overhead of multiple calls to initialize the style properties on each measurement.
14052          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14053          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14054          * in order to accurately measure the text height
14055          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14056          */
14057         createInstance : function(el, fixedWidth){
14058             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14059         }
14060     };
14061 }();
14062
14063  
14064
14065 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14066     var ml = new Roo.Element(document.createElement('div'));
14067     document.body.appendChild(ml.dom);
14068     ml.position('absolute');
14069     ml.setLeftTop(-1000, -1000);
14070     ml.hide();
14071
14072     if(fixedWidth){
14073         ml.setWidth(fixedWidth);
14074     }
14075      
14076     var instance = {
14077         /**
14078          * Returns the size of the specified text based on the internal element's style and width properties
14079          * @memberOf Roo.util.TextMetrics.Instance#
14080          * @param {String} text The text to measure
14081          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14082          */
14083         getSize : function(text){
14084             ml.update(text);
14085             var s = ml.getSize();
14086             ml.update('');
14087             return s;
14088         },
14089
14090         /**
14091          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14092          * that can affect the size of the rendered text
14093          * @memberOf Roo.util.TextMetrics.Instance#
14094          * @param {String/HTMLElement} el The element, dom node or id
14095          */
14096         bind : function(el){
14097             ml.setStyle(
14098                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14099             );
14100         },
14101
14102         /**
14103          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14104          * to set a fixed width in order to accurately measure the text height.
14105          * @memberOf Roo.util.TextMetrics.Instance#
14106          * @param {Number} width The width to set on the element
14107          */
14108         setFixedWidth : function(width){
14109             ml.setWidth(width);
14110         },
14111
14112         /**
14113          * Returns the measured width of the specified text
14114          * @memberOf Roo.util.TextMetrics.Instance#
14115          * @param {String} text The text to measure
14116          * @return {Number} width The width in pixels
14117          */
14118         getWidth : function(text){
14119             ml.dom.style.width = 'auto';
14120             return this.getSize(text).width;
14121         },
14122
14123         /**
14124          * Returns the measured height of the specified text.  For multiline text, be sure to call
14125          * {@link #setFixedWidth} if necessary.
14126          * @memberOf Roo.util.TextMetrics.Instance#
14127          * @param {String} text The text to measure
14128          * @return {Number} height The height in pixels
14129          */
14130         getHeight : function(text){
14131             return this.getSize(text).height;
14132         }
14133     };
14134
14135     instance.bind(bindTo);
14136
14137     return instance;
14138 };
14139
14140 // backwards compat
14141 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14142  * Based on:
14143  * Ext JS Library 1.1.1
14144  * Copyright(c) 2006-2007, Ext JS, LLC.
14145  *
14146  * Originally Released Under LGPL - original licence link has changed is not relivant.
14147  *
14148  * Fork - LGPL
14149  * <script type="text/javascript">
14150  */
14151
14152 /**
14153  * @class Roo.state.Provider
14154  * Abstract base class for state provider implementations. This class provides methods
14155  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14156  * Provider interface.
14157  */
14158 Roo.state.Provider = function(){
14159     /**
14160      * @event statechange
14161      * Fires when a state change occurs.
14162      * @param {Provider} this This state provider
14163      * @param {String} key The state key which was changed
14164      * @param {String} value The encoded value for the state
14165      */
14166     this.addEvents({
14167         "statechange": true
14168     });
14169     this.state = {};
14170     Roo.state.Provider.superclass.constructor.call(this);
14171 };
14172 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14173     /**
14174      * Returns the current value for a key
14175      * @param {String} name The key name
14176      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14177      * @return {Mixed} The state data
14178      */
14179     get : function(name, defaultValue){
14180         return typeof this.state[name] == "undefined" ?
14181             defaultValue : this.state[name];
14182     },
14183     
14184     /**
14185      * Clears a value from the state
14186      * @param {String} name The key name
14187      */
14188     clear : function(name){
14189         delete this.state[name];
14190         this.fireEvent("statechange", this, name, null);
14191     },
14192     
14193     /**
14194      * Sets the value for a key
14195      * @param {String} name The key name
14196      * @param {Mixed} value The value to set
14197      */
14198     set : function(name, value){
14199         this.state[name] = value;
14200         this.fireEvent("statechange", this, name, value);
14201     },
14202     
14203     /**
14204      * Decodes a string previously encoded with {@link #encodeValue}.
14205      * @param {String} value The value to decode
14206      * @return {Mixed} The decoded value
14207      */
14208     decodeValue : function(cookie){
14209         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14210         var matches = re.exec(unescape(cookie));
14211         if(!matches || !matches[1]) return; // non state cookie
14212         var type = matches[1];
14213         var v = matches[2];
14214         switch(type){
14215             case "n":
14216                 return parseFloat(v);
14217             case "d":
14218                 return new Date(Date.parse(v));
14219             case "b":
14220                 return (v == "1");
14221             case "a":
14222                 var all = [];
14223                 var values = v.split("^");
14224                 for(var i = 0, len = values.length; i < len; i++){
14225                     all.push(this.decodeValue(values[i]));
14226                 }
14227                 return all;
14228            case "o":
14229                 var all = {};
14230                 var values = v.split("^");
14231                 for(var i = 0, len = values.length; i < len; i++){
14232                     var kv = values[i].split("=");
14233                     all[kv[0]] = this.decodeValue(kv[1]);
14234                 }
14235                 return all;
14236            default:
14237                 return v;
14238         }
14239     },
14240     
14241     /**
14242      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14243      * @param {Mixed} value The value to encode
14244      * @return {String} The encoded value
14245      */
14246     encodeValue : function(v){
14247         var enc;
14248         if(typeof v == "number"){
14249             enc = "n:" + v;
14250         }else if(typeof v == "boolean"){
14251             enc = "b:" + (v ? "1" : "0");
14252         }else if(v instanceof Date){
14253             enc = "d:" + v.toGMTString();
14254         }else if(v instanceof Array){
14255             var flat = "";
14256             for(var i = 0, len = v.length; i < len; i++){
14257                 flat += this.encodeValue(v[i]);
14258                 if(i != len-1) flat += "^";
14259             }
14260             enc = "a:" + flat;
14261         }else if(typeof v == "object"){
14262             var flat = "";
14263             for(var key in v){
14264                 if(typeof v[key] != "function"){
14265                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14266                 }
14267             }
14268             enc = "o:" + flat.substring(0, flat.length-1);
14269         }else{
14270             enc = "s:" + v;
14271         }
14272         return escape(enc);        
14273     }
14274 });
14275
14276 /*
14277  * Based on:
14278  * Ext JS Library 1.1.1
14279  * Copyright(c) 2006-2007, Ext JS, LLC.
14280  *
14281  * Originally Released Under LGPL - original licence link has changed is not relivant.
14282  *
14283  * Fork - LGPL
14284  * <script type="text/javascript">
14285  */
14286 /**
14287  * @class Roo.state.Manager
14288  * This is the global state manager. By default all components that are "state aware" check this class
14289  * for state information if you don't pass them a custom state provider. In order for this class
14290  * to be useful, it must be initialized with a provider when your application initializes.
14291  <pre><code>
14292 // in your initialization function
14293 init : function(){
14294    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14295    ...
14296    // supposed you have a {@link Roo.BorderLayout}
14297    var layout = new Roo.BorderLayout(...);
14298    layout.restoreState();
14299    // or a {Roo.BasicDialog}
14300    var dialog = new Roo.BasicDialog(...);
14301    dialog.restoreState();
14302  </code></pre>
14303  * @singleton
14304  */
14305 Roo.state.Manager = function(){
14306     var provider = new Roo.state.Provider();
14307     
14308     return {
14309         /**
14310          * Configures the default state provider for your application
14311          * @param {Provider} stateProvider The state provider to set
14312          */
14313         setProvider : function(stateProvider){
14314             provider = stateProvider;
14315         },
14316         
14317         /**
14318          * Returns the current value for a key
14319          * @param {String} name The key name
14320          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14321          * @return {Mixed} The state data
14322          */
14323         get : function(key, defaultValue){
14324             return provider.get(key, defaultValue);
14325         },
14326         
14327         /**
14328          * Sets the value for a key
14329          * @param {String} name The key name
14330          * @param {Mixed} value The state data
14331          */
14332          set : function(key, value){
14333             provider.set(key, value);
14334         },
14335         
14336         /**
14337          * Clears a value from the state
14338          * @param {String} name The key name
14339          */
14340         clear : function(key){
14341             provider.clear(key);
14342         },
14343         
14344         /**
14345          * Gets the currently configured state provider
14346          * @return {Provider} The state provider
14347          */
14348         getProvider : function(){
14349             return provider;
14350         }
14351     };
14352 }();
14353 /*
14354  * Based on:
14355  * Ext JS Library 1.1.1
14356  * Copyright(c) 2006-2007, Ext JS, LLC.
14357  *
14358  * Originally Released Under LGPL - original licence link has changed is not relivant.
14359  *
14360  * Fork - LGPL
14361  * <script type="text/javascript">
14362  */
14363 /**
14364  * @class Roo.state.CookieProvider
14365  * @extends Roo.state.Provider
14366  * The default Provider implementation which saves state via cookies.
14367  * <br />Usage:
14368  <pre><code>
14369    var cp = new Roo.state.CookieProvider({
14370        path: "/cgi-bin/",
14371        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14372        domain: "roojs.com"
14373    })
14374    Roo.state.Manager.setProvider(cp);
14375  </code></pre>
14376  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14377  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14378  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14379  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14380  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14381  * domain the page is running on including the 'www' like 'www.roojs.com')
14382  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14383  * @constructor
14384  * Create a new CookieProvider
14385  * @param {Object} config The configuration object
14386  */
14387 Roo.state.CookieProvider = function(config){
14388     Roo.state.CookieProvider.superclass.constructor.call(this);
14389     this.path = "/";
14390     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14391     this.domain = null;
14392     this.secure = false;
14393     Roo.apply(this, config);
14394     this.state = this.readCookies();
14395 };
14396
14397 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14398     // private
14399     set : function(name, value){
14400         if(typeof value == "undefined" || value === null){
14401             this.clear(name);
14402             return;
14403         }
14404         this.setCookie(name, value);
14405         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14406     },
14407
14408     // private
14409     clear : function(name){
14410         this.clearCookie(name);
14411         Roo.state.CookieProvider.superclass.clear.call(this, name);
14412     },
14413
14414     // private
14415     readCookies : function(){
14416         var cookies = {};
14417         var c = document.cookie + ";";
14418         var re = /\s?(.*?)=(.*?);/g;
14419         var matches;
14420         while((matches = re.exec(c)) != null){
14421             var name = matches[1];
14422             var value = matches[2];
14423             if(name && name.substring(0,3) == "ys-"){
14424                 cookies[name.substr(3)] = this.decodeValue(value);
14425             }
14426         }
14427         return cookies;
14428     },
14429
14430     // private
14431     setCookie : function(name, value){
14432         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14433            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14434            ((this.path == null) ? "" : ("; path=" + this.path)) +
14435            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14436            ((this.secure == true) ? "; secure" : "");
14437     },
14438
14439     // private
14440     clearCookie : function(name){
14441         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14442            ((this.path == null) ? "" : ("; path=" + this.path)) +
14443            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14444            ((this.secure == true) ? "; secure" : "");
14445     }
14446 });