roojs-core-debug.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618
619         /**
620          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621          * you may want to set this to true.
622          * @type Boolean
623          */
624         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
625         
626         
627                 
628         /**
629          * Selects a single element as a Roo Element
630          * This is about as close as you can get to jQuery's $('do crazy stuff')
631          * @param {String} selector The selector/xpath query
632          * @param {Node} root (optional) The start of the query (defaults to document).
633          * @return {Roo.Element}
634          */
635         selectNode : function(selector, root) 
636         {
637             var node = Roo.DomQuery.selectNode(selector,root);
638             return node ? Roo.get(node) : new Roo.Element(false);
639         }
640         
641     });
642
643
644 })();
645
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
648 /*
649  * Based on:
650  * Ext JS Library 1.1.1
651  * Copyright(c) 2006-2007, Ext JS, LLC.
652  *
653  * Originally Released Under LGPL - original licence link has changed is not relivant.
654  *
655  * Fork - LGPL
656  * <script type="text/javascript">
657  */
658
659 (function() {    
660     // wrappedn so fnCleanup is not in global scope...
661     if(Roo.isIE) {
662         function fnCleanUp() {
663             var p = Function.prototype;
664             delete p.createSequence;
665             delete p.defer;
666             delete p.createDelegate;
667             delete p.createCallback;
668             delete p.createInterceptor;
669
670             window.detachEvent("onunload", fnCleanUp);
671         }
672         window.attachEvent("onunload", fnCleanUp);
673     }
674 })();
675
676
677 /**
678  * @class Function
679  * These functions are available on every Function object (any JavaScript function).
680  */
681 Roo.apply(Function.prototype, {
682      /**
683      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685      * Will create a function that is bound to those 2 args.
686      * @return {Function} The new function
687     */
688     createCallback : function(/*args...*/){
689         // make args available, in function below
690         var args = arguments;
691         var method = this;
692         return function() {
693             return method.apply(window, args);
694         };
695     },
696
697     /**
698      * Creates a delegate (callback) that sets the scope to obj.
699      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700      * Will create a function that is automatically scoped to this.
701      * @param {Object} obj (optional) The object for which the scope is set
702      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704      *                                             if a number the args are inserted at the specified position
705      * @return {Function} The new function
706      */
707     createDelegate : function(obj, args, appendArgs){
708         var method = this;
709         return function() {
710             var callArgs = args || arguments;
711             if(appendArgs === true){
712                 callArgs = Array.prototype.slice.call(arguments, 0);
713                 callArgs = callArgs.concat(args);
714             }else if(typeof appendArgs == "number"){
715                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
718             }
719             return method.apply(obj || window, callArgs);
720         };
721     },
722
723     /**
724      * Calls this function after the number of millseconds specified.
725      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726      * @param {Object} obj (optional) The object for which the scope is set
727      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729      *                                             if a number the args are inserted at the specified position
730      * @return {Number} The timeout id that can be used with clearTimeout
731      */
732     defer : function(millis, obj, args, appendArgs){
733         var fn = this.createDelegate(obj, args, appendArgs);
734         if(millis){
735             return setTimeout(fn, millis);
736         }
737         fn();
738         return 0;
739     },
740     /**
741      * Create a combined function call sequence of the original function + the passed function.
742      * The resulting function returns the results of the original function.
743      * The passed fcn is called with the parameters of the original function
744      * @param {Function} fcn The function to sequence
745      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746      * @return {Function} The new function
747      */
748     createSequence : function(fcn, scope){
749         if(typeof fcn != "function"){
750             return this;
751         }
752         var method = this;
753         return function() {
754             var retval = method.apply(this || window, arguments);
755             fcn.apply(scope || this || window, arguments);
756             return retval;
757         };
758     },
759
760     /**
761      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762      * The resulting function returns the results of the original function.
763      * The passed fcn is called with the parameters of the original function.
764      * @addon
765      * @param {Function} fcn The function to call before the original
766      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767      * @return {Function} The new function
768      */
769     createInterceptor : function(fcn, scope){
770         if(typeof fcn != "function"){
771             return this;
772         }
773         var method = this;
774         return function() {
775             fcn.target = this;
776             fcn.method = method;
777             if(fcn.apply(scope || this || window, arguments) === false){
778                 return;
779             }
780             return method.apply(this || window, arguments);
781         };
782     }
783 });
784 /*
785  * Based on:
786  * Ext JS Library 1.1.1
787  * Copyright(c) 2006-2007, Ext JS, LLC.
788  *
789  * Originally Released Under LGPL - original licence link has changed is not relivant.
790  *
791  * Fork - LGPL
792  * <script type="text/javascript">
793  */
794
795 Roo.applyIf(String, {
796     
797     /** @scope String */
798     
799     /**
800      * Escapes the passed string for ' and \
801      * @param {String} string The string to escape
802      * @return {String} The escaped string
803      * @static
804      */
805     escape : function(string) {
806         return string.replace(/('|\\)/g, "\\$1");
807     },
808
809     /**
810      * Pads the left side of a string with a specified character.  This is especially useful
811      * for normalizing number and date strings.  Example usage:
812      * <pre><code>
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
815 </code></pre>
816      * @param {String} string The original string
817      * @param {Number} size The total length of the output string
818      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819      * @return {String} The padded string
820      * @static
821      */
822     leftPad : function (val, size, ch) {
823         var result = new String(val);
824         if(ch === null || ch === undefined || ch === '') {
825             ch = " ";
826         }
827         while (result.length < size) {
828             result = ch + result;
829         }
830         return result;
831     },
832
833     /**
834      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
835      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
836      * <pre><code>
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
840 </code></pre>
841      * @param {String} string The tokenized string to be formatted
842      * @param {String} value1 The value to replace token {0}
843      * @param {String} value2 Etc...
844      * @return {String} The formatted string
845      * @static
846      */
847     format : function(format){
848         var args = Array.prototype.slice.call(arguments, 1);
849         return format.replace(/\{(\d+)\}/g, function(m, i){
850             return Roo.util.Format.htmlEncode(args[i]);
851         });
852     }
853 });
854
855 /**
856  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
857  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
858  * they are already different, the first value passed in is returned.  Note that this method returns the new value
859  * but does not change the current string.
860  * <pre><code>
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
863
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
866 </code></pre>
867  * @param {String} value The value to compare to the current string
868  * @param {String} other The new value to use if the string already equals the first value passed in
869  * @return {String} The new value
870  */
871  
872 String.prototype.toggle = function(value, other){
873     return this == value ? other : value;
874 };/*
875  * Based on:
876  * Ext JS Library 1.1.1
877  * Copyright(c) 2006-2007, Ext JS, LLC.
878  *
879  * Originally Released Under LGPL - original licence link has changed is not relivant.
880  *
881  * Fork - LGPL
882  * <script type="text/javascript">
883  */
884
885  /**
886  * @class Number
887  */
888 Roo.applyIf(Number.prototype, {
889     /**
890      * Checks whether or not the current number is within a desired range.  If the number is already within the
891      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892      * exceeded.  Note that this method returns the constrained value but does not change the current number.
893      * @param {Number} min The minimum number in the range
894      * @param {Number} max The maximum number in the range
895      * @return {Number} The constrained value if outside the range, otherwise the current value
896      */
897     constrain : function(min, max){
898         return Math.min(Math.max(this, min), max);
899     }
900 });/*
901  * Based on:
902  * Ext JS Library 1.1.1
903  * Copyright(c) 2006-2007, Ext JS, LLC.
904  *
905  * Originally Released Under LGPL - original licence link has changed is not relivant.
906  *
907  * Fork - LGPL
908  * <script type="text/javascript">
909  */
910  /**
911  * @class Array
912  */
913 Roo.applyIf(Array.prototype, {
914     /**
915      * Checks whether or not the specified object exists in the array.
916      * @param {Object} o The object to check for
917      * @return {Number} The index of o in the array (or -1 if it is not found)
918      */
919     indexOf : function(o){
920        for (var i = 0, len = this.length; i < len; i++){
921               if(this[i] == o) return i;
922        }
923            return -1;
924     },
925
926     /**
927      * Removes the specified object from the array.  If the object is not found nothing happens.
928      * @param {Object} o The object to remove
929      */
930     remove : function(o){
931        var index = this.indexOf(o);
932        if(index != -1){
933            this.splice(index, 1);
934        }
935     },
936     /**
937      * Map (JS 1.6 compatibility)
938      * @param {Function} function  to call
939      */
940     map : function(fun )
941     {
942         var len = this.length >>> 0;
943         if (typeof fun != "function")
944             throw new TypeError();
945
946         var res = new Array(len);
947         var thisp = arguments[1];
948         for (var i = 0; i < len; i++)
949         {
950             if (i in this)
951                 res[i] = fun.call(thisp, this[i], i, this);
952         }
953
954         return res;
955     }
956     
957 });
958
959
960  /*
961  * Based on:
962  * Ext JS Library 1.1.1
963  * Copyright(c) 2006-2007, Ext JS, LLC.
964  *
965  * Originally Released Under LGPL - original licence link has changed is not relivant.
966  *
967  * Fork - LGPL
968  * <script type="text/javascript">
969  */
970
971 /**
972  * @class Date
973  *
974  * The date parsing and format syntax is a subset of
975  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976  * supported will provide results equivalent to their PHP versions.
977  *
978  * Following is the list of all currently supported formats:
979  *<pre>
980 Sample date:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
982
983 Format  Output      Description
984 ------  ----------  --------------------------------------------------------------
985   d      10         Day of the month, 2 digits with leading zeros
986   D      Wed        A textual representation of a day, three letters
987   j      10         Day of the month without leading zeros
988   l      Wednesday  A full textual representation of the day of the week
989   S      th         English ordinal day of month suffix, 2 chars (use with j)
990   w      3          Numeric representation of the day of the week
991   z      9          The julian date, or day of the year (0-365)
992   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993   F      January    A full textual representation of the month
994   m      01         Numeric representation of a month, with leading zeros
995   M      Jan        Month name abbreviation, three letters
996   n      1          Numeric representation of a month, without leading zeros
997   t      31         Number of days in the given month
998   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
999   Y      2007       A full numeric representation of a year, 4 digits
1000   y      07         A two digit representation of a year
1001   a      pm         Lowercase Ante meridiem and Post meridiem
1002   A      PM         Uppercase Ante meridiem and Post meridiem
1003   g      3          12-hour format of an hour without leading zeros
1004   G      15         24-hour format of an hour without leading zeros
1005   h      03         12-hour format of an hour with leading zeros
1006   H      15         24-hour format of an hour with leading zeros
1007   i      05         Minutes with leading zeros
1008   s      01         Seconds, with leading zeros
1009   O      -0600      Difference to Greenwich time (GMT) in hours
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 // nasty IE9 hack - what a pile of crap that is..
4031
4032  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4033     Range.prototype.createContextualFragment = function (html) {
4034         var doc = window.document;
4035         var container = doc.createElement("div");
4036         container.innerHTML = html;
4037         var frag = doc.createDocumentFragment(), n;
4038         while ((n = container.firstChild)) {
4039             frag.appendChild(n);
4040         }
4041         return frag;
4042     };
4043 }
4044
4045 /**
4046  * @class Roo.DomHelper
4047  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4048  * 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>.
4049  * @singleton
4050  */
4051 Roo.DomHelper = function(){
4052     var tempTableEl = null;
4053     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4054     var tableRe = /^table|tbody|tr|td$/i;
4055     var xmlns = {};
4056     // build as innerHTML where available
4057     /** @ignore */
4058     var createHtml = function(o){
4059         if(typeof o == 'string'){
4060             return o;
4061         }
4062         var b = "";
4063         if(!o.tag){
4064             o.tag = "div";
4065         }
4066         b += "<" + o.tag;
4067         for(var attr in o){
4068             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4069             if(attr == "style"){
4070                 var s = o["style"];
4071                 if(typeof s == "function"){
4072                     s = s.call();
4073                 }
4074                 if(typeof s == "string"){
4075                     b += ' style="' + s + '"';
4076                 }else if(typeof s == "object"){
4077                     b += ' style="';
4078                     for(var key in s){
4079                         if(typeof s[key] != "function"){
4080                             b += key + ":" + s[key] + ";";
4081                         }
4082                     }
4083                     b += '"';
4084                 }
4085             }else{
4086                 if(attr == "cls"){
4087                     b += ' class="' + o["cls"] + '"';
4088                 }else if(attr == "htmlFor"){
4089                     b += ' for="' + o["htmlFor"] + '"';
4090                 }else{
4091                     b += " " + attr + '="' + o[attr] + '"';
4092                 }
4093             }
4094         }
4095         if(emptyTags.test(o.tag)){
4096             b += "/>";
4097         }else{
4098             b += ">";
4099             var cn = o.children || o.cn;
4100             if(cn){
4101                 //http://bugs.kde.org/show_bug.cgi?id=71506
4102                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4103                     for(var i = 0, len = cn.length; i < len; i++) {
4104                         b += createHtml(cn[i], b);
4105                     }
4106                 }else{
4107                     b += createHtml(cn, b);
4108                 }
4109             }
4110             if(o.html){
4111                 b += o.html;
4112             }
4113             b += "</" + o.tag + ">";
4114         }
4115         return b;
4116     };
4117
4118     // build as dom
4119     /** @ignore */
4120     var createDom = function(o, parentNode){
4121          
4122         // defininition craeted..
4123         var ns = false;
4124         if (o.ns && o.ns != 'html') {
4125                
4126             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4127                 xmlns[o.ns] = o.xmlns;
4128                 ns = o.xmlns;
4129             }
4130             if (typeof(xmlns[o.ns]) == 'undefined') {
4131                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4132             }
4133             ns = xmlns[o.ns];
4134         }
4135         
4136         
4137         if (typeof(o) == 'string') {
4138             return parentNode.appendChild(document.createTextNode(o));
4139         }
4140         o.tag = o.tag || div;
4141         if (o.ns && Roo.isIE) {
4142             ns = false;
4143             o.tag = o.ns + ':' + o.tag;
4144             
4145         }
4146         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4147         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4148         for(var attr in o){
4149             
4150             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4151                     attr == "style" || typeof o[attr] == "function") continue;
4152                     
4153             if(attr=="cls" && Roo.isIE){
4154                 el.className = o["cls"];
4155             }else{
4156                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4157                 else el[attr] = o[attr];
4158             }
4159         }
4160         Roo.DomHelper.applyStyles(el, o.style);
4161         var cn = o.children || o.cn;
4162         if(cn){
4163             //http://bugs.kde.org/show_bug.cgi?id=71506
4164              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4165                 for(var i = 0, len = cn.length; i < len; i++) {
4166                     createDom(cn[i], el);
4167                 }
4168             }else{
4169                 createDom(cn, el);
4170             }
4171         }
4172         if(o.html){
4173             el.innerHTML = o.html;
4174         }
4175         if(parentNode){
4176            parentNode.appendChild(el);
4177         }
4178         return el;
4179     };
4180
4181     var ieTable = function(depth, s, h, e){
4182         tempTableEl.innerHTML = [s, h, e].join('');
4183         var i = -1, el = tempTableEl;
4184         while(++i < depth){
4185             el = el.firstChild;
4186         }
4187         return el;
4188     };
4189
4190     // kill repeat to save bytes
4191     var ts = '<table>',
4192         te = '</table>',
4193         tbs = ts+'<tbody>',
4194         tbe = '</tbody>'+te,
4195         trs = tbs + '<tr>',
4196         tre = '</tr>'+tbe;
4197
4198     /**
4199      * @ignore
4200      * Nasty code for IE's broken table implementation
4201      */
4202     var insertIntoTable = function(tag, where, el, html){
4203         if(!tempTableEl){
4204             tempTableEl = document.createElement('div');
4205         }
4206         var node;
4207         var before = null;
4208         if(tag == 'td'){
4209             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4210                 return;
4211             }
4212             if(where == 'beforebegin'){
4213                 before = el;
4214                 el = el.parentNode;
4215             } else{
4216                 before = el.nextSibling;
4217                 el = el.parentNode;
4218             }
4219             node = ieTable(4, trs, html, tre);
4220         }
4221         else if(tag == 'tr'){
4222             if(where == 'beforebegin'){
4223                 before = el;
4224                 el = el.parentNode;
4225                 node = ieTable(3, tbs, html, tbe);
4226             } else if(where == 'afterend'){
4227                 before = el.nextSibling;
4228                 el = el.parentNode;
4229                 node = ieTable(3, tbs, html, tbe);
4230             } else{ // INTO a TR
4231                 if(where == 'afterbegin'){
4232                     before = el.firstChild;
4233                 }
4234                 node = ieTable(4, trs, html, tre);
4235             }
4236         } else if(tag == 'tbody'){
4237             if(where == 'beforebegin'){
4238                 before = el;
4239                 el = el.parentNode;
4240                 node = ieTable(2, ts, html, te);
4241             } else if(where == 'afterend'){
4242                 before = el.nextSibling;
4243                 el = el.parentNode;
4244                 node = ieTable(2, ts, html, te);
4245             } else{
4246                 if(where == 'afterbegin'){
4247                     before = el.firstChild;
4248                 }
4249                 node = ieTable(3, tbs, html, tbe);
4250             }
4251         } else{ // TABLE
4252             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4253                 return;
4254             }
4255             if(where == 'afterbegin'){
4256                 before = el.firstChild;
4257             }
4258             node = ieTable(2, ts, html, te);
4259         }
4260         el.insertBefore(node, before);
4261         return node;
4262     };
4263
4264     return {
4265     /** True to force the use of DOM instead of html fragments @type Boolean */
4266     useDom : false,
4267
4268     /**
4269      * Returns the markup for the passed Element(s) config
4270      * @param {Object} o The Dom object spec (and children)
4271      * @return {String}
4272      */
4273     markup : function(o){
4274         return createHtml(o);
4275     },
4276
4277     /**
4278      * Applies a style specification to an element
4279      * @param {String/HTMLElement} el The element to apply styles to
4280      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4281      * a function which returns such a specification.
4282      */
4283     applyStyles : function(el, styles){
4284         if(styles){
4285            el = Roo.fly(el);
4286            if(typeof styles == "string"){
4287                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4288                var matches;
4289                while ((matches = re.exec(styles)) != null){
4290                    el.setStyle(matches[1], matches[2]);
4291                }
4292            }else if (typeof styles == "object"){
4293                for (var style in styles){
4294                   el.setStyle(style, styles[style]);
4295                }
4296            }else if (typeof styles == "function"){
4297                 Roo.DomHelper.applyStyles(el, styles.call());
4298            }
4299         }
4300     },
4301
4302     /**
4303      * Inserts an HTML fragment into the Dom
4304      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4305      * @param {HTMLElement} el The context element
4306      * @param {String} html The HTML fragmenet
4307      * @return {HTMLElement} The new node
4308      */
4309     insertHtml : function(where, el, html){
4310         where = where.toLowerCase();
4311         if(el.insertAdjacentHTML){
4312             if(tableRe.test(el.tagName)){
4313                 var rs;
4314                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4315                     return rs;
4316                 }
4317             }
4318             switch(where){
4319                 case "beforebegin":
4320                     el.insertAdjacentHTML('BeforeBegin', html);
4321                     return el.previousSibling;
4322                 case "afterbegin":
4323                     el.insertAdjacentHTML('AfterBegin', html);
4324                     return el.firstChild;
4325                 case "beforeend":
4326                     el.insertAdjacentHTML('BeforeEnd', html);
4327                     return el.lastChild;
4328                 case "afterend":
4329                     el.insertAdjacentHTML('AfterEnd', html);
4330                     return el.nextSibling;
4331             }
4332             throw 'Illegal insertion point -> "' + where + '"';
4333         }
4334         var range = el.ownerDocument.createRange();
4335         var frag;
4336         switch(where){
4337              case "beforebegin":
4338                 range.setStartBefore(el);
4339                 frag = range.createContextualFragment(html);
4340                 el.parentNode.insertBefore(frag, el);
4341                 return el.previousSibling;
4342              case "afterbegin":
4343                 if(el.firstChild){
4344                     range.setStartBefore(el.firstChild);
4345                     frag = range.createContextualFragment(html);
4346                     el.insertBefore(frag, el.firstChild);
4347                     return el.firstChild;
4348                 }else{
4349                     el.innerHTML = html;
4350                     return el.firstChild;
4351                 }
4352             case "beforeend":
4353                 if(el.lastChild){
4354                     range.setStartAfter(el.lastChild);
4355                     frag = range.createContextualFragment(html);
4356                     el.appendChild(frag);
4357                     return el.lastChild;
4358                 }else{
4359                     el.innerHTML = html;
4360                     return el.lastChild;
4361                 }
4362             case "afterend":
4363                 range.setStartAfter(el);
4364                 frag = range.createContextualFragment(html);
4365                 el.parentNode.insertBefore(frag, el.nextSibling);
4366                 return el.nextSibling;
4367             }
4368             throw 'Illegal insertion point -> "' + where + '"';
4369     },
4370
4371     /**
4372      * Creates new Dom element(s) and inserts them before el
4373      * @param {String/HTMLElement/Element} el The context element
4374      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4375      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4376      * @return {HTMLElement/Roo.Element} The new node
4377      */
4378     insertBefore : function(el, o, returnElement){
4379         return this.doInsert(el, o, returnElement, "beforeBegin");
4380     },
4381
4382     /**
4383      * Creates new Dom element(s) and inserts them after el
4384      * @param {String/HTMLElement/Element} el The context element
4385      * @param {Object} o The Dom object spec (and children)
4386      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4387      * @return {HTMLElement/Roo.Element} The new node
4388      */
4389     insertAfter : function(el, o, returnElement){
4390         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4391     },
4392
4393     /**
4394      * Creates new Dom element(s) and inserts them as the first child of el
4395      * @param {String/HTMLElement/Element} el The context element
4396      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4397      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4398      * @return {HTMLElement/Roo.Element} The new node
4399      */
4400     insertFirst : function(el, o, returnElement){
4401         return this.doInsert(el, o, returnElement, "afterBegin");
4402     },
4403
4404     // private
4405     doInsert : function(el, o, returnElement, pos, sibling){
4406         el = Roo.getDom(el);
4407         var newNode;
4408         if(this.useDom || o.ns){
4409             newNode = createDom(o, null);
4410             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4411         }else{
4412             var html = createHtml(o);
4413             newNode = this.insertHtml(pos, el, html);
4414         }
4415         return returnElement ? Roo.get(newNode, true) : newNode;
4416     },
4417
4418     /**
4419      * Creates new Dom element(s) and appends them to el
4420      * @param {String/HTMLElement/Element} el The context element
4421      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4422      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4423      * @return {HTMLElement/Roo.Element} The new node
4424      */
4425     append : function(el, o, returnElement){
4426         el = Roo.getDom(el);
4427         var newNode;
4428         if(this.useDom || o.ns){
4429             newNode = createDom(o, null);
4430             el.appendChild(newNode);
4431         }else{
4432             var html = createHtml(o);
4433             newNode = this.insertHtml("beforeEnd", el, html);
4434         }
4435         return returnElement ? Roo.get(newNode, true) : newNode;
4436     },
4437
4438     /**
4439      * Creates new Dom element(s) and overwrites the contents of el with them
4440      * @param {String/HTMLElement/Element} el The context element
4441      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4442      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4443      * @return {HTMLElement/Roo.Element} The new node
4444      */
4445     overwrite : function(el, o, returnElement){
4446         el = Roo.getDom(el);
4447         if (o.ns) {
4448           
4449             while (el.childNodes.length) {
4450                 el.removeChild(el.firstChild);
4451             }
4452             createDom(o, el);
4453         } else {
4454             el.innerHTML = createHtml(o);   
4455         }
4456         
4457         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4458     },
4459
4460     /**
4461      * Creates a new Roo.DomHelper.Template from the Dom object spec
4462      * @param {Object} o The Dom object spec (and children)
4463      * @return {Roo.DomHelper.Template} The new template
4464      */
4465     createTemplate : function(o){
4466         var html = createHtml(o);
4467         return new Roo.Template(html);
4468     }
4469     };
4470 }();
4471 /*
4472  * Based on:
4473  * Ext JS Library 1.1.1
4474  * Copyright(c) 2006-2007, Ext JS, LLC.
4475  *
4476  * Originally Released Under LGPL - original licence link has changed is not relivant.
4477  *
4478  * Fork - LGPL
4479  * <script type="text/javascript">
4480  */
4481  
4482 /**
4483 * @class Roo.Template
4484 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4485 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4486 * Usage:
4487 <pre><code>
4488 var t = new Roo.Template({
4489     html :  '&lt;div name="{id}"&gt;' + 
4490         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4491         '&lt;/div&gt;',
4492     myformat: function (value, allValues) {
4493         return 'XX' + value;
4494     }
4495 });
4496 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4497 </code></pre>
4498 * 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>. 
4499 * @constructor
4500 * @param {Object} cfg - Configuration object.
4501 */
4502 Roo.Template = function(cfg){
4503     // BC!
4504     if(cfg instanceof Array){
4505         cfg = cfg.join("");
4506     }else if(arguments.length > 1){
4507         cfg = Array.prototype.join.call(arguments, "");
4508     }
4509     
4510     
4511     if (typeof(cfg) == 'object') {
4512         Roo.apply(this,cfg)
4513     } else {
4514         // bc
4515         this.html = cfg;
4516     }
4517     
4518     
4519 };
4520 Roo.Template.prototype = {
4521     
4522     /**
4523      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4524      */
4525     html : '',
4526     /**
4527      * Returns an HTML fragment of this template with the specified values applied.
4528      * @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'})
4529      * @return {String} The HTML fragment
4530      */
4531     applyTemplate : function(values){
4532         try {
4533             
4534             if(this.compiled){
4535                 return this.compiled(values);
4536             }
4537             var useF = this.disableFormats !== true;
4538             var fm = Roo.util.Format, tpl = this;
4539             var fn = function(m, name, format, args){
4540                 if(format && useF){
4541                     if(format.substr(0, 5) == "this."){
4542                         return tpl.call(format.substr(5), values[name], values);
4543                     }else{
4544                         if(args){
4545                             // quoted values are required for strings in compiled templates, 
4546                             // but for non compiled we need to strip them
4547                             // quoted reversed for jsmin
4548                             var re = /^\s*['"](.*)["']\s*$/;
4549                             args = args.split(',');
4550                             for(var i = 0, len = args.length; i < len; i++){
4551                                 args[i] = args[i].replace(re, "$1");
4552                             }
4553                             args = [values[name]].concat(args);
4554                         }else{
4555                             args = [values[name]];
4556                         }
4557                         return fm[format].apply(fm, args);
4558                     }
4559                 }else{
4560                     return values[name] !== undefined ? values[name] : "";
4561                 }
4562             };
4563             return this.html.replace(this.re, fn);
4564         } catch (e) {
4565             Roo.log(e);
4566             throw e;
4567         }
4568          
4569     },
4570     
4571     /**
4572      * Sets the HTML used as the template and optionally compiles it.
4573      * @param {String} html
4574      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4575      * @return {Roo.Template} this
4576      */
4577     set : function(html, compile){
4578         this.html = html;
4579         this.compiled = null;
4580         if(compile){
4581             this.compile();
4582         }
4583         return this;
4584     },
4585     
4586     /**
4587      * True to disable format functions (defaults to false)
4588      * @type Boolean
4589      */
4590     disableFormats : false,
4591     
4592     /**
4593     * The regular expression used to match template variables 
4594     * @type RegExp
4595     * @property 
4596     */
4597     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4598     
4599     /**
4600      * Compiles the template into an internal function, eliminating the RegEx overhead.
4601      * @return {Roo.Template} this
4602      */
4603     compile : function(){
4604         var fm = Roo.util.Format;
4605         var useF = this.disableFormats !== true;
4606         var sep = Roo.isGecko ? "+" : ",";
4607         var fn = function(m, name, format, args){
4608             if(format && useF){
4609                 args = args ? ',' + args : "";
4610                 if(format.substr(0, 5) != "this."){
4611                     format = "fm." + format + '(';
4612                 }else{
4613                     format = 'this.call("'+ format.substr(5) + '", ';
4614                     args = ", values";
4615                 }
4616             }else{
4617                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4618             }
4619             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4620         };
4621         var body;
4622         // branched to use + in gecko and [].join() in others
4623         if(Roo.isGecko){
4624             body = "this.compiled = function(values){ return '" +
4625                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4626                     "';};";
4627         }else{
4628             body = ["this.compiled = function(values){ return ['"];
4629             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4630             body.push("'].join('');};");
4631             body = body.join('');
4632         }
4633         /**
4634          * eval:var:values
4635          * eval:var:fm
4636          */
4637         eval(body);
4638         return this;
4639     },
4640     
4641     // private function used to call members
4642     call : function(fnName, value, allValues){
4643         return this[fnName](value, allValues);
4644     },
4645     
4646     /**
4647      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4648      * @param {String/HTMLElement/Roo.Element} el The context element
4649      * @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'})
4650      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4651      * @return {HTMLElement/Roo.Element} The new node or Element
4652      */
4653     insertFirst: function(el, values, returnElement){
4654         return this.doInsert('afterBegin', el, values, returnElement);
4655     },
4656
4657     /**
4658      * Applies the supplied values to the template and inserts the new node(s) before el.
4659      * @param {String/HTMLElement/Roo.Element} el The context element
4660      * @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'})
4661      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4662      * @return {HTMLElement/Roo.Element} The new node or Element
4663      */
4664     insertBefore: function(el, values, returnElement){
4665         return this.doInsert('beforeBegin', el, values, returnElement);
4666     },
4667
4668     /**
4669      * Applies the supplied values to the template and inserts the new node(s) after el.
4670      * @param {String/HTMLElement/Roo.Element} el The context element
4671      * @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'})
4672      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4673      * @return {HTMLElement/Roo.Element} The new node or Element
4674      */
4675     insertAfter : function(el, values, returnElement){
4676         return this.doInsert('afterEnd', el, values, returnElement);
4677     },
4678     
4679     /**
4680      * Applies the supplied values to the template and appends the new node(s) to el.
4681      * @param {String/HTMLElement/Roo.Element} el The context element
4682      * @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'})
4683      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4684      * @return {HTMLElement/Roo.Element} The new node or Element
4685      */
4686     append : function(el, values, returnElement){
4687         return this.doInsert('beforeEnd', el, values, returnElement);
4688     },
4689
4690     doInsert : function(where, el, values, returnEl){
4691         el = Roo.getDom(el);
4692         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4693         return returnEl ? Roo.get(newNode, true) : newNode;
4694     },
4695
4696     /**
4697      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4698      * @param {String/HTMLElement/Roo.Element} el The context element
4699      * @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'})
4700      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4701      * @return {HTMLElement/Roo.Element} The new node or Element
4702      */
4703     overwrite : function(el, values, returnElement){
4704         el = Roo.getDom(el);
4705         el.innerHTML = this.applyTemplate(values);
4706         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4707     }
4708 };
4709 /**
4710  * Alias for {@link #applyTemplate}
4711  * @method
4712  */
4713 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4714
4715 // backwards compat
4716 Roo.DomHelper.Template = Roo.Template;
4717
4718 /**
4719  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4720  * @param {String/HTMLElement} el A DOM element or its id
4721  * @returns {Roo.Template} The created template
4722  * @static
4723  */
4724 Roo.Template.from = function(el){
4725     el = Roo.getDom(el);
4726     return new Roo.Template(el.value || el.innerHTML);
4727 };/*
4728  * Based on:
4729  * Ext JS Library 1.1.1
4730  * Copyright(c) 2006-2007, Ext JS, LLC.
4731  *
4732  * Originally Released Under LGPL - original licence link has changed is not relivant.
4733  *
4734  * Fork - LGPL
4735  * <script type="text/javascript">
4736  */
4737  
4738
4739 /*
4740  * This is code is also distributed under MIT license for use
4741  * with jQuery and prototype JavaScript libraries.
4742  */
4743 /**
4744  * @class Roo.DomQuery
4745 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).
4746 <p>
4747 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>
4748
4749 <p>
4750 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.
4751 </p>
4752 <h4>Element Selectors:</h4>
4753 <ul class="list">
4754     <li> <b>*</b> any element</li>
4755     <li> <b>E</b> an element with the tag E</li>
4756     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4757     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4758     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4759     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4760 </ul>
4761 <h4>Attribute Selectors:</h4>
4762 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4763 <ul class="list">
4764     <li> <b>E[foo]</b> has an attribute "foo"</li>
4765     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4766     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4767     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4768     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4769     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4770     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4771 </ul>
4772 <h4>Pseudo Classes:</h4>
4773 <ul class="list">
4774     <li> <b>E:first-child</b> E is the first child of its parent</li>
4775     <li> <b>E:last-child</b> E is the last child of its parent</li>
4776     <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>
4777     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4778     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4779     <li> <b>E:only-child</b> E is the only child of its parent</li>
4780     <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>
4781     <li> <b>E:first</b> the first E in the resultset</li>
4782     <li> <b>E:last</b> the last E in the resultset</li>
4783     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4784     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4785     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4786     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4787     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4788     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4789     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4790     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4791     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4792 </ul>
4793 <h4>CSS Value Selectors:</h4>
4794 <ul class="list">
4795     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4796     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4797     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4798     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4799     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4800     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4801 </ul>
4802  * @singleton
4803  */
4804 Roo.DomQuery = function(){
4805     var cache = {}, simpleCache = {}, valueCache = {};
4806     var nonSpace = /\S/;
4807     var trimRe = /^\s+|\s+$/g;
4808     var tplRe = /\{(\d+)\}/g;
4809     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4810     var tagTokenRe = /^(#)?([\w-\*]+)/;
4811     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4812
4813     function child(p, index){
4814         var i = 0;
4815         var n = p.firstChild;
4816         while(n){
4817             if(n.nodeType == 1){
4818                if(++i == index){
4819                    return n;
4820                }
4821             }
4822             n = n.nextSibling;
4823         }
4824         return null;
4825     };
4826
4827     function next(n){
4828         while((n = n.nextSibling) && n.nodeType != 1);
4829         return n;
4830     };
4831
4832     function prev(n){
4833         while((n = n.previousSibling) && n.nodeType != 1);
4834         return n;
4835     };
4836
4837     function children(d){
4838         var n = d.firstChild, ni = -1;
4839             while(n){
4840                 var nx = n.nextSibling;
4841                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4842                     d.removeChild(n);
4843                 }else{
4844                     n.nodeIndex = ++ni;
4845                 }
4846                 n = nx;
4847             }
4848             return this;
4849         };
4850
4851     function byClassName(c, a, v){
4852         if(!v){
4853             return c;
4854         }
4855         var r = [], ri = -1, cn;
4856         for(var i = 0, ci; ci = c[i]; i++){
4857             if((' '+ci.className+' ').indexOf(v) != -1){
4858                 r[++ri] = ci;
4859             }
4860         }
4861         return r;
4862     };
4863
4864     function attrValue(n, attr){
4865         if(!n.tagName && typeof n.length != "undefined"){
4866             n = n[0];
4867         }
4868         if(!n){
4869             return null;
4870         }
4871         if(attr == "for"){
4872             return n.htmlFor;
4873         }
4874         if(attr == "class" || attr == "className"){
4875             return n.className;
4876         }
4877         return n.getAttribute(attr) || n[attr];
4878
4879     };
4880
4881     function getNodes(ns, mode, tagName){
4882         var result = [], ri = -1, cs;
4883         if(!ns){
4884             return result;
4885         }
4886         tagName = tagName || "*";
4887         if(typeof ns.getElementsByTagName != "undefined"){
4888             ns = [ns];
4889         }
4890         if(!mode){
4891             for(var i = 0, ni; ni = ns[i]; i++){
4892                 cs = ni.getElementsByTagName(tagName);
4893                 for(var j = 0, ci; ci = cs[j]; j++){
4894                     result[++ri] = ci;
4895                 }
4896             }
4897         }else if(mode == "/" || mode == ">"){
4898             var utag = tagName.toUpperCase();
4899             for(var i = 0, ni, cn; ni = ns[i]; i++){
4900                 cn = ni.children || ni.childNodes;
4901                 for(var j = 0, cj; cj = cn[j]; j++){
4902                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4903                         result[++ri] = cj;
4904                     }
4905                 }
4906             }
4907         }else if(mode == "+"){
4908             var utag = tagName.toUpperCase();
4909             for(var i = 0, n; n = ns[i]; i++){
4910                 while((n = n.nextSibling) && n.nodeType != 1);
4911                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4912                     result[++ri] = n;
4913                 }
4914             }
4915         }else if(mode == "~"){
4916             for(var i = 0, n; n = ns[i]; i++){
4917                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4918                 if(n){
4919                     result[++ri] = n;
4920                 }
4921             }
4922         }
4923         return result;
4924     };
4925
4926     function concat(a, b){
4927         if(b.slice){
4928             return a.concat(b);
4929         }
4930         for(var i = 0, l = b.length; i < l; i++){
4931             a[a.length] = b[i];
4932         }
4933         return a;
4934     }
4935
4936     function byTag(cs, tagName){
4937         if(cs.tagName || cs == document){
4938             cs = [cs];
4939         }
4940         if(!tagName){
4941             return cs;
4942         }
4943         var r = [], ri = -1;
4944         tagName = tagName.toLowerCase();
4945         for(var i = 0, ci; ci = cs[i]; i++){
4946             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4947                 r[++ri] = ci;
4948             }
4949         }
4950         return r;
4951     };
4952
4953     function byId(cs, attr, id){
4954         if(cs.tagName || cs == document){
4955             cs = [cs];
4956         }
4957         if(!id){
4958             return cs;
4959         }
4960         var r = [], ri = -1;
4961         for(var i = 0,ci; ci = cs[i]; i++){
4962             if(ci && ci.id == id){
4963                 r[++ri] = ci;
4964                 return r;
4965             }
4966         }
4967         return r;
4968     };
4969
4970     function byAttribute(cs, attr, value, op, custom){
4971         var r = [], ri = -1, st = custom=="{";
4972         var f = Roo.DomQuery.operators[op];
4973         for(var i = 0, ci; ci = cs[i]; i++){
4974             var a;
4975             if(st){
4976                 a = Roo.DomQuery.getStyle(ci, attr);
4977             }
4978             else if(attr == "class" || attr == "className"){
4979                 a = ci.className;
4980             }else if(attr == "for"){
4981                 a = ci.htmlFor;
4982             }else if(attr == "href"){
4983                 a = ci.getAttribute("href", 2);
4984             }else{
4985                 a = ci.getAttribute(attr);
4986             }
4987             if((f && f(a, value)) || (!f && a)){
4988                 r[++ri] = ci;
4989             }
4990         }
4991         return r;
4992     };
4993
4994     function byPseudo(cs, name, value){
4995         return Roo.DomQuery.pseudos[name](cs, value);
4996     };
4997
4998     // This is for IE MSXML which does not support expandos.
4999     // IE runs the same speed using setAttribute, however FF slows way down
5000     // and Safari completely fails so they need to continue to use expandos.
5001     var isIE = window.ActiveXObject ? true : false;
5002
5003     // this eval is stop the compressor from
5004     // renaming the variable to something shorter
5005     
5006     /** eval:var:batch */
5007     var batch = 30803; 
5008
5009     var key = 30803;
5010
5011     function nodupIEXml(cs){
5012         var d = ++key;
5013         cs[0].setAttribute("_nodup", d);
5014         var r = [cs[0]];
5015         for(var i = 1, len = cs.length; i < len; i++){
5016             var c = cs[i];
5017             if(!c.getAttribute("_nodup") != d){
5018                 c.setAttribute("_nodup", d);
5019                 r[r.length] = c;
5020             }
5021         }
5022         for(var i = 0, len = cs.length; i < len; i++){
5023             cs[i].removeAttribute("_nodup");
5024         }
5025         return r;
5026     }
5027
5028     function nodup(cs){
5029         if(!cs){
5030             return [];
5031         }
5032         var len = cs.length, c, i, r = cs, cj, ri = -1;
5033         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5034             return cs;
5035         }
5036         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5037             return nodupIEXml(cs);
5038         }
5039         var d = ++key;
5040         cs[0]._nodup = d;
5041         for(i = 1; c = cs[i]; i++){
5042             if(c._nodup != d){
5043                 c._nodup = d;
5044             }else{
5045                 r = [];
5046                 for(var j = 0; j < i; j++){
5047                     r[++ri] = cs[j];
5048                 }
5049                 for(j = i+1; cj = cs[j]; j++){
5050                     if(cj._nodup != d){
5051                         cj._nodup = d;
5052                         r[++ri] = cj;
5053                     }
5054                 }
5055                 return r;
5056             }
5057         }
5058         return r;
5059     }
5060
5061     function quickDiffIEXml(c1, c2){
5062         var d = ++key;
5063         for(var i = 0, len = c1.length; i < len; i++){
5064             c1[i].setAttribute("_qdiff", d);
5065         }
5066         var r = [];
5067         for(var i = 0, len = c2.length; i < len; i++){
5068             if(c2[i].getAttribute("_qdiff") != d){
5069                 r[r.length] = c2[i];
5070             }
5071         }
5072         for(var i = 0, len = c1.length; i < len; i++){
5073            c1[i].removeAttribute("_qdiff");
5074         }
5075         return r;
5076     }
5077
5078     function quickDiff(c1, c2){
5079         var len1 = c1.length;
5080         if(!len1){
5081             return c2;
5082         }
5083         if(isIE && c1[0].selectSingleNode){
5084             return quickDiffIEXml(c1, c2);
5085         }
5086         var d = ++key;
5087         for(var i = 0; i < len1; i++){
5088             c1[i]._qdiff = d;
5089         }
5090         var r = [];
5091         for(var i = 0, len = c2.length; i < len; i++){
5092             if(c2[i]._qdiff != d){
5093                 r[r.length] = c2[i];
5094             }
5095         }
5096         return r;
5097     }
5098
5099     function quickId(ns, mode, root, id){
5100         if(ns == root){
5101            var d = root.ownerDocument || root;
5102            return d.getElementById(id);
5103         }
5104         ns = getNodes(ns, mode, "*");
5105         return byId(ns, null, id);
5106     }
5107
5108     return {
5109         getStyle : function(el, name){
5110             return Roo.fly(el).getStyle(name);
5111         },
5112         /**
5113          * Compiles a selector/xpath query into a reusable function. The returned function
5114          * takes one parameter "root" (optional), which is the context node from where the query should start.
5115          * @param {String} selector The selector/xpath query
5116          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5117          * @return {Function}
5118          */
5119         compile : function(path, type){
5120             type = type || "select";
5121             
5122             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5123             var q = path, mode, lq;
5124             var tk = Roo.DomQuery.matchers;
5125             var tklen = tk.length;
5126             var mm;
5127
5128             // accept leading mode switch
5129             var lmode = q.match(modeRe);
5130             if(lmode && lmode[1]){
5131                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5132                 q = q.replace(lmode[1], "");
5133             }
5134             // strip leading slashes
5135             while(path.substr(0, 1)=="/"){
5136                 path = path.substr(1);
5137             }
5138
5139             while(q && lq != q){
5140                 lq = q;
5141                 var tm = q.match(tagTokenRe);
5142                 if(type == "select"){
5143                     if(tm){
5144                         if(tm[1] == "#"){
5145                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5146                         }else{
5147                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5148                         }
5149                         q = q.replace(tm[0], "");
5150                     }else if(q.substr(0, 1) != '@'){
5151                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5152                     }
5153                 }else{
5154                     if(tm){
5155                         if(tm[1] == "#"){
5156                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5157                         }else{
5158                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5159                         }
5160                         q = q.replace(tm[0], "");
5161                     }
5162                 }
5163                 while(!(mm = q.match(modeRe))){
5164                     var matched = false;
5165                     for(var j = 0; j < tklen; j++){
5166                         var t = tk[j];
5167                         var m = q.match(t.re);
5168                         if(m){
5169                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5170                                                     return m[i];
5171                                                 });
5172                             q = q.replace(m[0], "");
5173                             matched = true;
5174                             break;
5175                         }
5176                     }
5177                     // prevent infinite loop on bad selector
5178                     if(!matched){
5179                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5180                     }
5181                 }
5182                 if(mm[1]){
5183                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5184                     q = q.replace(mm[1], "");
5185                 }
5186             }
5187             fn[fn.length] = "return nodup(n);\n}";
5188             
5189              /** 
5190               * list of variables that need from compression as they are used by eval.
5191              *  eval:var:batch 
5192              *  eval:var:nodup
5193              *  eval:var:byTag
5194              *  eval:var:ById
5195              *  eval:var:getNodes
5196              *  eval:var:quickId
5197              *  eval:var:mode
5198              *  eval:var:root
5199              *  eval:var:n
5200              *  eval:var:byClassName
5201              *  eval:var:byPseudo
5202              *  eval:var:byAttribute
5203              *  eval:var:attrValue
5204              * 
5205              **/ 
5206             eval(fn.join(""));
5207             return f;
5208         },
5209
5210         /**
5211          * Selects a group of elements.
5212          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5213          * @param {Node} root (optional) The start of the query (defaults to document).
5214          * @return {Array}
5215          */
5216         select : function(path, root, type){
5217             if(!root || root == document){
5218                 root = document;
5219             }
5220             if(typeof root == "string"){
5221                 root = document.getElementById(root);
5222             }
5223             var paths = path.split(",");
5224             var results = [];
5225             for(var i = 0, len = paths.length; i < len; i++){
5226                 var p = paths[i].replace(trimRe, "");
5227                 if(!cache[p]){
5228                     cache[p] = Roo.DomQuery.compile(p);
5229                     if(!cache[p]){
5230                         throw p + " is not a valid selector";
5231                     }
5232                 }
5233                 var result = cache[p](root);
5234                 if(result && result != document){
5235                     results = results.concat(result);
5236                 }
5237             }
5238             if(paths.length > 1){
5239                 return nodup(results);
5240             }
5241             return results;
5242         },
5243
5244         /**
5245          * Selects a single element.
5246          * @param {String} selector The selector/xpath query
5247          * @param {Node} root (optional) The start of the query (defaults to document).
5248          * @return {Element}
5249          */
5250         selectNode : function(path, root){
5251             return Roo.DomQuery.select(path, root)[0];
5252         },
5253
5254         /**
5255          * Selects the value of a node, optionally replacing null with the defaultValue.
5256          * @param {String} selector The selector/xpath query
5257          * @param {Node} root (optional) The start of the query (defaults to document).
5258          * @param {String} defaultValue
5259          */
5260         selectValue : function(path, root, defaultValue){
5261             path = path.replace(trimRe, "");
5262             if(!valueCache[path]){
5263                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5264             }
5265             var n = valueCache[path](root);
5266             n = n[0] ? n[0] : n;
5267             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5268             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5269         },
5270
5271         /**
5272          * Selects the value of a node, parsing integers and floats.
5273          * @param {String} selector The selector/xpath query
5274          * @param {Node} root (optional) The start of the query (defaults to document).
5275          * @param {Number} defaultValue
5276          * @return {Number}
5277          */
5278         selectNumber : function(path, root, defaultValue){
5279             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5280             return parseFloat(v);
5281         },
5282
5283         /**
5284          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5285          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5286          * @param {String} selector The simple selector to test
5287          * @return {Boolean}
5288          */
5289         is : function(el, ss){
5290             if(typeof el == "string"){
5291                 el = document.getElementById(el);
5292             }
5293             var isArray = (el instanceof Array);
5294             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5295             return isArray ? (result.length == el.length) : (result.length > 0);
5296         },
5297
5298         /**
5299          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5300          * @param {Array} el An array of elements to filter
5301          * @param {String} selector The simple selector to test
5302          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5303          * the selector instead of the ones that match
5304          * @return {Array}
5305          */
5306         filter : function(els, ss, nonMatches){
5307             ss = ss.replace(trimRe, "");
5308             if(!simpleCache[ss]){
5309                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5310             }
5311             var result = simpleCache[ss](els);
5312             return nonMatches ? quickDiff(result, els) : result;
5313         },
5314
5315         /**
5316          * Collection of matching regular expressions and code snippets.
5317          */
5318         matchers : [{
5319                 re: /^\.([\w-]+)/,
5320                 select: 'n = byClassName(n, null, " {1} ");'
5321             }, {
5322                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5323                 select: 'n = byPseudo(n, "{1}", "{2}");'
5324             },{
5325                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5326                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5327             }, {
5328                 re: /^#([\w-]+)/,
5329                 select: 'n = byId(n, null, "{1}");'
5330             },{
5331                 re: /^@([\w-]+)/,
5332                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5333             }
5334         ],
5335
5336         /**
5337          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5338          * 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;.
5339          */
5340         operators : {
5341             "=" : function(a, v){
5342                 return a == v;
5343             },
5344             "!=" : function(a, v){
5345                 return a != v;
5346             },
5347             "^=" : function(a, v){
5348                 return a && a.substr(0, v.length) == v;
5349             },
5350             "$=" : function(a, v){
5351                 return a && a.substr(a.length-v.length) == v;
5352             },
5353             "*=" : function(a, v){
5354                 return a && a.indexOf(v) !== -1;
5355             },
5356             "%=" : function(a, v){
5357                 return (a % v) == 0;
5358             },
5359             "|=" : function(a, v){
5360                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5361             },
5362             "~=" : function(a, v){
5363                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5364             }
5365         },
5366
5367         /**
5368          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5369          * and the argument (if any) supplied in the selector.
5370          */
5371         pseudos : {
5372             "first-child" : function(c){
5373                 var r = [], ri = -1, n;
5374                 for(var i = 0, ci; ci = n = c[i]; i++){
5375                     while((n = n.previousSibling) && n.nodeType != 1);
5376                     if(!n){
5377                         r[++ri] = ci;
5378                     }
5379                 }
5380                 return r;
5381             },
5382
5383             "last-child" : function(c){
5384                 var r = [], ri = -1, n;
5385                 for(var i = 0, ci; ci = n = c[i]; i++){
5386                     while((n = n.nextSibling) && n.nodeType != 1);
5387                     if(!n){
5388                         r[++ri] = ci;
5389                     }
5390                 }
5391                 return r;
5392             },
5393
5394             "nth-child" : function(c, a) {
5395                 var r = [], ri = -1;
5396                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5397                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5398                 for(var i = 0, n; n = c[i]; i++){
5399                     var pn = n.parentNode;
5400                     if (batch != pn._batch) {
5401                         var j = 0;
5402                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5403                             if(cn.nodeType == 1){
5404                                cn.nodeIndex = ++j;
5405                             }
5406                         }
5407                         pn._batch = batch;
5408                     }
5409                     if (f == 1) {
5410                         if (l == 0 || n.nodeIndex == l){
5411                             r[++ri] = n;
5412                         }
5413                     } else if ((n.nodeIndex + l) % f == 0){
5414                         r[++ri] = n;
5415                     }
5416                 }
5417
5418                 return r;
5419             },
5420
5421             "only-child" : function(c){
5422                 var r = [], ri = -1;;
5423                 for(var i = 0, ci; ci = c[i]; i++){
5424                     if(!prev(ci) && !next(ci)){
5425                         r[++ri] = ci;
5426                     }
5427                 }
5428                 return r;
5429             },
5430
5431             "empty" : function(c){
5432                 var r = [], ri = -1;
5433                 for(var i = 0, ci; ci = c[i]; i++){
5434                     var cns = ci.childNodes, j = 0, cn, empty = true;
5435                     while(cn = cns[j]){
5436                         ++j;
5437                         if(cn.nodeType == 1 || cn.nodeType == 3){
5438                             empty = false;
5439                             break;
5440                         }
5441                     }
5442                     if(empty){
5443                         r[++ri] = ci;
5444                     }
5445                 }
5446                 return r;
5447             },
5448
5449             "contains" : function(c, v){
5450                 var r = [], ri = -1;
5451                 for(var i = 0, ci; ci = c[i]; i++){
5452                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5453                         r[++ri] = ci;
5454                     }
5455                 }
5456                 return r;
5457             },
5458
5459             "nodeValue" : function(c, v){
5460                 var r = [], ri = -1;
5461                 for(var i = 0, ci; ci = c[i]; i++){
5462                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5463                         r[++ri] = ci;
5464                     }
5465                 }
5466                 return r;
5467             },
5468
5469             "checked" : function(c){
5470                 var r = [], ri = -1;
5471                 for(var i = 0, ci; ci = c[i]; i++){
5472                     if(ci.checked == true){
5473                         r[++ri] = ci;
5474                     }
5475                 }
5476                 return r;
5477             },
5478
5479             "not" : function(c, ss){
5480                 return Roo.DomQuery.filter(c, ss, true);
5481             },
5482
5483             "odd" : function(c){
5484                 return this["nth-child"](c, "odd");
5485             },
5486
5487             "even" : function(c){
5488                 return this["nth-child"](c, "even");
5489             },
5490
5491             "nth" : function(c, a){
5492                 return c[a-1] || [];
5493             },
5494
5495             "first" : function(c){
5496                 return c[0] || [];
5497             },
5498
5499             "last" : function(c){
5500                 return c[c.length-1] || [];
5501             },
5502
5503             "has" : function(c, ss){
5504                 var s = Roo.DomQuery.select;
5505                 var r = [], ri = -1;
5506                 for(var i = 0, ci; ci = c[i]; i++){
5507                     if(s(ss, ci).length > 0){
5508                         r[++ri] = ci;
5509                     }
5510                 }
5511                 return r;
5512             },
5513
5514             "next" : function(c, ss){
5515                 var is = Roo.DomQuery.is;
5516                 var r = [], ri = -1;
5517                 for(var i = 0, ci; ci = c[i]; i++){
5518                     var n = next(ci);
5519                     if(n && is(n, ss)){
5520                         r[++ri] = ci;
5521                     }
5522                 }
5523                 return r;
5524             },
5525
5526             "prev" : function(c, ss){
5527                 var is = Roo.DomQuery.is;
5528                 var r = [], ri = -1;
5529                 for(var i = 0, ci; ci = c[i]; i++){
5530                     var n = prev(ci);
5531                     if(n && is(n, ss)){
5532                         r[++ri] = ci;
5533                     }
5534                 }
5535                 return r;
5536             }
5537         }
5538     };
5539 }();
5540
5541 /**
5542  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5543  * @param {String} path The selector/xpath query
5544  * @param {Node} root (optional) The start of the query (defaults to document).
5545  * @return {Array}
5546  * @member Roo
5547  * @method query
5548  */
5549 Roo.query = Roo.DomQuery.select;
5550 /*
5551  * Based on:
5552  * Ext JS Library 1.1.1
5553  * Copyright(c) 2006-2007, Ext JS, LLC.
5554  *
5555  * Originally Released Under LGPL - original licence link has changed is not relivant.
5556  *
5557  * Fork - LGPL
5558  * <script type="text/javascript">
5559  */
5560
5561 /**
5562  * @class Roo.util.Observable
5563  * Base class that provides a common interface for publishing events. Subclasses are expected to
5564  * to have a property "events" with all the events defined.<br>
5565  * For example:
5566  * <pre><code>
5567  Employee = function(name){
5568     this.name = name;
5569     this.addEvents({
5570         "fired" : true,
5571         "quit" : true
5572     });
5573  }
5574  Roo.extend(Employee, Roo.util.Observable);
5575 </code></pre>
5576  * @param {Object} config properties to use (incuding events / listeners)
5577  */
5578
5579 Roo.util.Observable = function(cfg){
5580     
5581     cfg = cfg|| {};
5582     this.addEvents(cfg.events || {});
5583     if (cfg.events) {
5584         delete cfg.events; // make sure
5585     }
5586      
5587     Roo.apply(this, cfg);
5588     
5589     if(this.listeners){
5590         this.on(this.listeners);
5591         delete this.listeners;
5592     }
5593 };
5594 Roo.util.Observable.prototype = {
5595     /** 
5596  * @cfg {Object} listeners  list of events and functions to call for this object, 
5597  * For example :
5598  * <pre><code>
5599     listeners :  { 
5600        'click' : function(e) {
5601            ..... 
5602         } ,
5603         .... 
5604     } 
5605   </code></pre>
5606  */
5607     
5608     
5609     /**
5610      * Fires the specified event with the passed parameters (minus the event name).
5611      * @param {String} eventName
5612      * @param {Object...} args Variable number of parameters are passed to handlers
5613      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5614      */
5615     fireEvent : function(){
5616         var ce = this.events[arguments[0].toLowerCase()];
5617         if(typeof ce == "object"){
5618             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5619         }else{
5620             return true;
5621         }
5622     },
5623
5624     // private
5625     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5626
5627     /**
5628      * Appends an event handler to this component
5629      * @param {String}   eventName The type of event to listen for
5630      * @param {Function} handler The method the event invokes
5631      * @param {Object}   scope (optional) The scope in which to execute the handler
5632      * function. The handler function's "this" context.
5633      * @param {Object}   options (optional) An object containing handler configuration
5634      * properties. This may contain any of the following properties:<ul>
5635      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5636      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5637      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5638      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5639      * by the specified number of milliseconds. If the event fires again within that time, the original
5640      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5641      * </ul><br>
5642      * <p>
5643      * <b>Combining Options</b><br>
5644      * Using the options argument, it is possible to combine different types of listeners:<br>
5645      * <br>
5646      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5647                 <pre><code>
5648                 el.on('click', this.onClick, this, {
5649                         single: true,
5650                 delay: 100,
5651                 forumId: 4
5652                 });
5653                 </code></pre>
5654      * <p>
5655      * <b>Attaching multiple handlers in 1 call</b><br>
5656      * The method also allows for a single argument to be passed which is a config object containing properties
5657      * which specify multiple handlers.
5658      * <pre><code>
5659                 el.on({
5660                         'click': {
5661                         fn: this.onClick,
5662                         scope: this,
5663                         delay: 100
5664                 }, 
5665                 'mouseover': {
5666                         fn: this.onMouseOver,
5667                         scope: this
5668                 },
5669                 'mouseout': {
5670                         fn: this.onMouseOut,
5671                         scope: this
5672                 }
5673                 });
5674                 </code></pre>
5675      * <p>
5676      * Or a shorthand syntax which passes the same scope object to all handlers:
5677         <pre><code>
5678                 el.on({
5679                         'click': this.onClick,
5680                 'mouseover': this.onMouseOver,
5681                 'mouseout': this.onMouseOut,
5682                 scope: this
5683                 });
5684                 </code></pre>
5685      */
5686     addListener : function(eventName, fn, scope, o){
5687         if(typeof eventName == "object"){
5688             o = eventName;
5689             for(var e in o){
5690                 if(this.filterOptRe.test(e)){
5691                     continue;
5692                 }
5693                 if(typeof o[e] == "function"){
5694                     // shared options
5695                     this.addListener(e, o[e], o.scope,  o);
5696                 }else{
5697                     // individual options
5698                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5699                 }
5700             }
5701             return;
5702         }
5703         o = (!o || typeof o == "boolean") ? {} : o;
5704         eventName = eventName.toLowerCase();
5705         var ce = this.events[eventName] || true;
5706         if(typeof ce == "boolean"){
5707             ce = new Roo.util.Event(this, eventName);
5708             this.events[eventName] = ce;
5709         }
5710         ce.addListener(fn, scope, o);
5711     },
5712
5713     /**
5714      * Removes a listener
5715      * @param {String}   eventName     The type of event to listen for
5716      * @param {Function} handler        The handler to remove
5717      * @param {Object}   scope  (optional) The scope (this object) for the handler
5718      */
5719     removeListener : function(eventName, fn, scope){
5720         var ce = this.events[eventName.toLowerCase()];
5721         if(typeof ce == "object"){
5722             ce.removeListener(fn, scope);
5723         }
5724     },
5725
5726     /**
5727      * Removes all listeners for this object
5728      */
5729     purgeListeners : function(){
5730         for(var evt in this.events){
5731             if(typeof this.events[evt] == "object"){
5732                  this.events[evt].clearListeners();
5733             }
5734         }
5735     },
5736
5737     relayEvents : function(o, events){
5738         var createHandler = function(ename){
5739             return function(){
5740                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5741             };
5742         };
5743         for(var i = 0, len = events.length; i < len; i++){
5744             var ename = events[i];
5745             if(!this.events[ename]){ this.events[ename] = true; };
5746             o.on(ename, createHandler(ename), this);
5747         }
5748     },
5749
5750     /**
5751      * Used to define events on this Observable
5752      * @param {Object} object The object with the events defined
5753      */
5754     addEvents : function(o){
5755         if(!this.events){
5756             this.events = {};
5757         }
5758         Roo.applyIf(this.events, o);
5759     },
5760
5761     /**
5762      * Checks to see if this object has any listeners for a specified event
5763      * @param {String} eventName The name of the event to check for
5764      * @return {Boolean} True if the event is being listened for, else false
5765      */
5766     hasListener : function(eventName){
5767         var e = this.events[eventName];
5768         return typeof e == "object" && e.listeners.length > 0;
5769     }
5770 };
5771 /**
5772  * Appends an event handler to this element (shorthand for addListener)
5773  * @param {String}   eventName     The type of event to listen for
5774  * @param {Function} handler        The method the event invokes
5775  * @param {Object}   scope (optional) The scope in which to execute the handler
5776  * function. The handler function's "this" context.
5777  * @param {Object}   options  (optional)
5778  * @method
5779  */
5780 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5781 /**
5782  * Removes a listener (shorthand for removeListener)
5783  * @param {String}   eventName     The type of event to listen for
5784  * @param {Function} handler        The handler to remove
5785  * @param {Object}   scope  (optional) The scope (this object) for the handler
5786  * @method
5787  */
5788 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5789
5790 /**
5791  * Starts capture on the specified Observable. All events will be passed
5792  * to the supplied function with the event name + standard signature of the event
5793  * <b>before</b> the event is fired. If the supplied function returns false,
5794  * the event will not fire.
5795  * @param {Observable} o The Observable to capture
5796  * @param {Function} fn The function to call
5797  * @param {Object} scope (optional) The scope (this object) for the fn
5798  * @static
5799  */
5800 Roo.util.Observable.capture = function(o, fn, scope){
5801     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5802 };
5803
5804 /**
5805  * Removes <b>all</b> added captures from the Observable.
5806  * @param {Observable} o The Observable to release
5807  * @static
5808  */
5809 Roo.util.Observable.releaseCapture = function(o){
5810     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5811 };
5812
5813 (function(){
5814
5815     var createBuffered = function(h, o, scope){
5816         var task = new Roo.util.DelayedTask();
5817         return function(){
5818             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5819         };
5820     };
5821
5822     var createSingle = function(h, e, fn, scope){
5823         return function(){
5824             e.removeListener(fn, scope);
5825             return h.apply(scope, arguments);
5826         };
5827     };
5828
5829     var createDelayed = function(h, o, scope){
5830         return function(){
5831             var args = Array.prototype.slice.call(arguments, 0);
5832             setTimeout(function(){
5833                 h.apply(scope, args);
5834             }, o.delay || 10);
5835         };
5836     };
5837
5838     Roo.util.Event = function(obj, name){
5839         this.name = name;
5840         this.obj = obj;
5841         this.listeners = [];
5842     };
5843
5844     Roo.util.Event.prototype = {
5845         addListener : function(fn, scope, options){
5846             var o = options || {};
5847             scope = scope || this.obj;
5848             if(!this.isListening(fn, scope)){
5849                 var l = {fn: fn, scope: scope, options: o};
5850                 var h = fn;
5851                 if(o.delay){
5852                     h = createDelayed(h, o, scope);
5853                 }
5854                 if(o.single){
5855                     h = createSingle(h, this, fn, scope);
5856                 }
5857                 if(o.buffer){
5858                     h = createBuffered(h, o, scope);
5859                 }
5860                 l.fireFn = h;
5861                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5862                     this.listeners.push(l);
5863                 }else{
5864                     this.listeners = this.listeners.slice(0);
5865                     this.listeners.push(l);
5866                 }
5867             }
5868         },
5869
5870         findListener : function(fn, scope){
5871             scope = scope || this.obj;
5872             var ls = this.listeners;
5873             for(var i = 0, len = ls.length; i < len; i++){
5874                 var l = ls[i];
5875                 if(l.fn == fn && l.scope == scope){
5876                     return i;
5877                 }
5878             }
5879             return -1;
5880         },
5881
5882         isListening : function(fn, scope){
5883             return this.findListener(fn, scope) != -1;
5884         },
5885
5886         removeListener : function(fn, scope){
5887             var index;
5888             if((index = this.findListener(fn, scope)) != -1){
5889                 if(!this.firing){
5890                     this.listeners.splice(index, 1);
5891                 }else{
5892                     this.listeners = this.listeners.slice(0);
5893                     this.listeners.splice(index, 1);
5894                 }
5895                 return true;
5896             }
5897             return false;
5898         },
5899
5900         clearListeners : function(){
5901             this.listeners = [];
5902         },
5903
5904         fire : function(){
5905             var ls = this.listeners, scope, len = ls.length;
5906             if(len > 0){
5907                 this.firing = true;
5908                 var args = Array.prototype.slice.call(arguments, 0);
5909                 for(var i = 0; i < len; i++){
5910                     var l = ls[i];
5911                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5912                         this.firing = false;
5913                         return false;
5914                     }
5915                 }
5916                 this.firing = false;
5917             }
5918             return true;
5919         }
5920     };
5921 })();/*
5922  * Based on:
5923  * Ext JS Library 1.1.1
5924  * Copyright(c) 2006-2007, Ext JS, LLC.
5925  *
5926  * Originally Released Under LGPL - original licence link has changed is not relivant.
5927  *
5928  * Fork - LGPL
5929  * <script type="text/javascript">
5930  */
5931
5932 /**
5933  * @class Roo.EventManager
5934  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5935  * several useful events directly.
5936  * See {@link Roo.EventObject} for more details on normalized event objects.
5937  * @singleton
5938  */
5939 Roo.EventManager = function(){
5940     var docReadyEvent, docReadyProcId, docReadyState = false;
5941     var resizeEvent, resizeTask, textEvent, textSize;
5942     var E = Roo.lib.Event;
5943     var D = Roo.lib.Dom;
5944
5945
5946     var fireDocReady = function(){
5947         if(!docReadyState){
5948             docReadyState = true;
5949             Roo.isReady = true;
5950             if(docReadyProcId){
5951                 clearInterval(docReadyProcId);
5952             }
5953             if(Roo.isGecko || Roo.isOpera) {
5954                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5955             }
5956             if(Roo.isIE){
5957                 var defer = document.getElementById("ie-deferred-loader");
5958                 if(defer){
5959                     defer.onreadystatechange = null;
5960                     defer.parentNode.removeChild(defer);
5961                 }
5962             }
5963             if(docReadyEvent){
5964                 docReadyEvent.fire();
5965                 docReadyEvent.clearListeners();
5966             }
5967         }
5968     };
5969     
5970     var initDocReady = function(){
5971         docReadyEvent = new Roo.util.Event();
5972         if(Roo.isGecko || Roo.isOpera) {
5973             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5974         }else if(Roo.isIE){
5975             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5976             var defer = document.getElementById("ie-deferred-loader");
5977             defer.onreadystatechange = function(){
5978                 if(this.readyState == "complete"){
5979                     fireDocReady();
5980                 }
5981             };
5982         }else if(Roo.isSafari){ 
5983             docReadyProcId = setInterval(function(){
5984                 var rs = document.readyState;
5985                 if(rs == "complete") {
5986                     fireDocReady();     
5987                  }
5988             }, 10);
5989         }
5990         // no matter what, make sure it fires on load
5991         E.on(window, "load", fireDocReady);
5992     };
5993
5994     var createBuffered = function(h, o){
5995         var task = new Roo.util.DelayedTask(h);
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             task.delay(o.buffer, h, null, [e]);
6000         };
6001     };
6002
6003     var createSingle = function(h, el, ename, fn){
6004         return function(e){
6005             Roo.EventManager.removeListener(el, ename, fn);
6006             h(e);
6007         };
6008     };
6009
6010     var createDelayed = function(h, o){
6011         return function(e){
6012             // create new event object impl so new events don't wipe out properties
6013             e = new Roo.EventObjectImpl(e);
6014             setTimeout(function(){
6015                 h(e);
6016             }, o.delay || 10);
6017         };
6018     };
6019
6020     var listen = function(element, ename, opt, fn, scope){
6021         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6022         fn = fn || o.fn; scope = scope || o.scope;
6023         var el = Roo.getDom(element);
6024         if(!el){
6025             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6026         }
6027         var h = function(e){
6028             e = Roo.EventObject.setEvent(e);
6029             var t;
6030             if(o.delegate){
6031                 t = e.getTarget(o.delegate, el);
6032                 if(!t){
6033                     return;
6034                 }
6035             }else{
6036                 t = e.target;
6037             }
6038             if(o.stopEvent === true){
6039                 e.stopEvent();
6040             }
6041             if(o.preventDefault === true){
6042                e.preventDefault();
6043             }
6044             if(o.stopPropagation === true){
6045                 e.stopPropagation();
6046             }
6047
6048             if(o.normalized === false){
6049                 e = e.browserEvent;
6050             }
6051
6052             fn.call(scope || el, e, t, o);
6053         };
6054         if(o.delay){
6055             h = createDelayed(h, o);
6056         }
6057         if(o.single){
6058             h = createSingle(h, el, ename, fn);
6059         }
6060         if(o.buffer){
6061             h = createBuffered(h, o);
6062         }
6063         fn._handlers = fn._handlers || [];
6064         fn._handlers.push([Roo.id(el), ename, h]);
6065
6066         E.on(el, ename, h);
6067         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6068             el.addEventListener("DOMMouseScroll", h, false);
6069             E.on(window, 'unload', function(){
6070                 el.removeEventListener("DOMMouseScroll", h, false);
6071             });
6072         }
6073         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6074             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6075         }
6076         return h;
6077     };
6078
6079     var stopListening = function(el, ename, fn){
6080         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6081         if(hds){
6082             for(var i = 0, len = hds.length; i < len; i++){
6083                 var h = hds[i];
6084                 if(h[0] == id && h[1] == ename){
6085                     hd = h[2];
6086                     hds.splice(i, 1);
6087                     break;
6088                 }
6089             }
6090         }
6091         E.un(el, ename, hd);
6092         el = Roo.getDom(el);
6093         if(ename == "mousewheel" && el.addEventListener){
6094             el.removeEventListener("DOMMouseScroll", hd, false);
6095         }
6096         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6097             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6098         }
6099     };
6100
6101     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6102     
6103     var pub = {
6104         
6105         
6106         /** 
6107          * Fix for doc tools
6108          * @scope Roo.EventManager
6109          */
6110         
6111         
6112         /** 
6113          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6114          * object with a Roo.EventObject
6115          * @param {Function} fn        The method the event invokes
6116          * @param {Object}   scope    An object that becomes the scope of the handler
6117          * @param {boolean}  override If true, the obj passed in becomes
6118          *                             the execution scope of the listener
6119          * @return {Function} The wrapped function
6120          * @deprecated
6121          */
6122         wrap : function(fn, scope, override){
6123             return function(e){
6124                 Roo.EventObject.setEvent(e);
6125                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6126             };
6127         },
6128         
6129         /**
6130      * Appends an event handler to an element (shorthand for addListener)
6131      * @param {String/HTMLElement}   element        The html element or id to assign the
6132      * @param {String}   eventName The type of event to listen for
6133      * @param {Function} handler The method the event invokes
6134      * @param {Object}   scope (optional) The scope in which to execute the handler
6135      * function. The handler function's "this" context.
6136      * @param {Object}   options (optional) An object containing handler configuration
6137      * properties. This may contain any of the following properties:<ul>
6138      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6139      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6140      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6141      * <li>preventDefault {Boolean} True to prevent the default action</li>
6142      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6143      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6144      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6145      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6146      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6147      * by the specified number of milliseconds. If the event fires again within that time, the original
6148      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6149      * </ul><br>
6150      * <p>
6151      * <b>Combining Options</b><br>
6152      * Using the options argument, it is possible to combine different types of listeners:<br>
6153      * <br>
6154      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6155      * Code:<pre><code>
6156 el.on('click', this.onClick, this, {
6157     single: true,
6158     delay: 100,
6159     stopEvent : true,
6160     forumId: 4
6161 });</code></pre>
6162      * <p>
6163      * <b>Attaching multiple handlers in 1 call</b><br>
6164       * The method also allows for a single argument to be passed which is a config object containing properties
6165      * which specify multiple handlers.
6166      * <p>
6167      * Code:<pre><code>
6168 el.on({
6169     'click' : {
6170         fn: this.onClick
6171         scope: this,
6172         delay: 100
6173     },
6174     'mouseover' : {
6175         fn: this.onMouseOver
6176         scope: this
6177     },
6178     'mouseout' : {
6179         fn: this.onMouseOut
6180         scope: this
6181     }
6182 });</code></pre>
6183      * <p>
6184      * Or a shorthand syntax:<br>
6185      * Code:<pre><code>
6186 el.on({
6187     'click' : this.onClick,
6188     'mouseover' : this.onMouseOver,
6189     'mouseout' : this.onMouseOut
6190     scope: this
6191 });</code></pre>
6192      */
6193         addListener : function(element, eventName, fn, scope, options){
6194             if(typeof eventName == "object"){
6195                 var o = eventName;
6196                 for(var e in o){
6197                     if(propRe.test(e)){
6198                         continue;
6199                     }
6200                     if(typeof o[e] == "function"){
6201                         // shared options
6202                         listen(element, e, o, o[e], o.scope);
6203                     }else{
6204                         // individual options
6205                         listen(element, e, o[e]);
6206                     }
6207                 }
6208                 return;
6209             }
6210             return listen(element, eventName, options, fn, scope);
6211         },
6212         
6213         /**
6214          * Removes an event handler
6215          *
6216          * @param {String/HTMLElement}   element        The id or html element to remove the 
6217          *                             event from
6218          * @param {String}   eventName     The type of event
6219          * @param {Function} fn
6220          * @return {Boolean} True if a listener was actually removed
6221          */
6222         removeListener : function(element, eventName, fn){
6223             return stopListening(element, eventName, fn);
6224         },
6225         
6226         /**
6227          * Fires when the document is ready (before onload and before images are loaded). Can be 
6228          * accessed shorthanded Roo.onReady().
6229          * @param {Function} fn        The method the event invokes
6230          * @param {Object}   scope    An  object that becomes the scope of the handler
6231          * @param {boolean}  options
6232          */
6233         onDocumentReady : function(fn, scope, options){
6234             if(docReadyState){ // if it already fired
6235                 docReadyEvent.addListener(fn, scope, options);
6236                 docReadyEvent.fire();
6237                 docReadyEvent.clearListeners();
6238                 return;
6239             }
6240             if(!docReadyEvent){
6241                 initDocReady();
6242             }
6243             docReadyEvent.addListener(fn, scope, options);
6244         },
6245         
6246         /**
6247          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6248          * @param {Function} fn        The method the event invokes
6249          * @param {Object}   scope    An object that becomes the scope of the handler
6250          * @param {boolean}  options
6251          */
6252         onWindowResize : function(fn, scope, options){
6253             if(!resizeEvent){
6254                 resizeEvent = new Roo.util.Event();
6255                 resizeTask = new Roo.util.DelayedTask(function(){
6256                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6257                 });
6258                 E.on(window, "resize", function(){
6259                     if(Roo.isIE){
6260                         resizeTask.delay(50);
6261                     }else{
6262                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6263                     }
6264                 });
6265             }
6266             resizeEvent.addListener(fn, scope, options);
6267         },
6268
6269         /**
6270          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6271          * @param {Function} fn        The method the event invokes
6272          * @param {Object}   scope    An object that becomes the scope of the handler
6273          * @param {boolean}  options
6274          */
6275         onTextResize : function(fn, scope, options){
6276             if(!textEvent){
6277                 textEvent = new Roo.util.Event();
6278                 var textEl = new Roo.Element(document.createElement('div'));
6279                 textEl.dom.className = 'x-text-resize';
6280                 textEl.dom.innerHTML = 'X';
6281                 textEl.appendTo(document.body);
6282                 textSize = textEl.dom.offsetHeight;
6283                 setInterval(function(){
6284                     if(textEl.dom.offsetHeight != textSize){
6285                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6286                     }
6287                 }, this.textResizeInterval);
6288             }
6289             textEvent.addListener(fn, scope, options);
6290         },
6291
6292         /**
6293          * Removes the passed window resize listener.
6294          * @param {Function} fn        The method the event invokes
6295          * @param {Object}   scope    The scope of handler
6296          */
6297         removeResizeListener : function(fn, scope){
6298             if(resizeEvent){
6299                 resizeEvent.removeListener(fn, scope);
6300             }
6301         },
6302
6303         // private
6304         fireResize : function(){
6305             if(resizeEvent){
6306                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6307             }   
6308         },
6309         /**
6310          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6311          */
6312         ieDeferSrc : false,
6313         /**
6314          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6315          */
6316         textResizeInterval : 50
6317     };
6318     
6319     /**
6320      * Fix for doc tools
6321      * @scopeAlias pub=Roo.EventManager
6322      */
6323     
6324      /**
6325      * Appends an event handler to an element (shorthand for addListener)
6326      * @param {String/HTMLElement}   element        The html element or id to assign the
6327      * @param {String}   eventName The type of event to listen for
6328      * @param {Function} handler The method the event invokes
6329      * @param {Object}   scope (optional) The scope in which to execute the handler
6330      * function. The handler function's "this" context.
6331      * @param {Object}   options (optional) An object containing handler configuration
6332      * properties. This may contain any of the following properties:<ul>
6333      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6334      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6335      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6336      * <li>preventDefault {Boolean} True to prevent the default action</li>
6337      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6338      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6339      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6340      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6341      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6342      * by the specified number of milliseconds. If the event fires again within that time, the original
6343      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6344      * </ul><br>
6345      * <p>
6346      * <b>Combining Options</b><br>
6347      * Using the options argument, it is possible to combine different types of listeners:<br>
6348      * <br>
6349      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6350      * Code:<pre><code>
6351 el.on('click', this.onClick, this, {
6352     single: true,
6353     delay: 100,
6354     stopEvent : true,
6355     forumId: 4
6356 });</code></pre>
6357      * <p>
6358      * <b>Attaching multiple handlers in 1 call</b><br>
6359       * The method also allows for a single argument to be passed which is a config object containing properties
6360      * which specify multiple handlers.
6361      * <p>
6362      * Code:<pre><code>
6363 el.on({
6364     'click' : {
6365         fn: this.onClick
6366         scope: this,
6367         delay: 100
6368     },
6369     'mouseover' : {
6370         fn: this.onMouseOver
6371         scope: this
6372     },
6373     'mouseout' : {
6374         fn: this.onMouseOut
6375         scope: this
6376     }
6377 });</code></pre>
6378      * <p>
6379      * Or a shorthand syntax:<br>
6380      * Code:<pre><code>
6381 el.on({
6382     'click' : this.onClick,
6383     'mouseover' : this.onMouseOver,
6384     'mouseout' : this.onMouseOut
6385     scope: this
6386 });</code></pre>
6387      */
6388     pub.on = pub.addListener;
6389     pub.un = pub.removeListener;
6390
6391     pub.stoppedMouseDownEvent = new Roo.util.Event();
6392     return pub;
6393 }();
6394 /**
6395   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6396   * @param {Function} fn        The method the event invokes
6397   * @param {Object}   scope    An  object that becomes the scope of the handler
6398   * @param {boolean}  override If true, the obj passed in becomes
6399   *                             the execution scope of the listener
6400   * @member Roo
6401   * @method onReady
6402  */
6403 Roo.onReady = Roo.EventManager.onDocumentReady;
6404
6405 Roo.onReady(function(){
6406     var bd = Roo.get(document.body);
6407     if(!bd){ return; }
6408
6409     var cls = [
6410             Roo.isIE ? "roo-ie"
6411             : Roo.isGecko ? "roo-gecko"
6412             : Roo.isOpera ? "roo-opera"
6413             : Roo.isSafari ? "roo-safari" : ""];
6414
6415     if(Roo.isMac){
6416         cls.push("roo-mac");
6417     }
6418     if(Roo.isLinux){
6419         cls.push("roo-linux");
6420     }
6421     if(Roo.isBorderBox){
6422         cls.push('roo-border-box');
6423     }
6424     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6425         var p = bd.dom.parentNode;
6426         if(p){
6427             p.className += ' roo-strict';
6428         }
6429     }
6430     bd.addClass(cls.join(' '));
6431 });
6432
6433 /**
6434  * @class Roo.EventObject
6435  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6436  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6437  * Example:
6438  * <pre><code>
6439  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6440     e.preventDefault();
6441     var target = e.getTarget();
6442     ...
6443  }
6444  var myDiv = Roo.get("myDiv");
6445  myDiv.on("click", handleClick);
6446  //or
6447  Roo.EventManager.on("myDiv", 'click', handleClick);
6448  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6449  </code></pre>
6450  * @singleton
6451  */
6452 Roo.EventObject = function(){
6453     
6454     var E = Roo.lib.Event;
6455     
6456     // safari keypress events for special keys return bad keycodes
6457     var safariKeys = {
6458         63234 : 37, // left
6459         63235 : 39, // right
6460         63232 : 38, // up
6461         63233 : 40, // down
6462         63276 : 33, // page up
6463         63277 : 34, // page down
6464         63272 : 46, // delete
6465         63273 : 36, // home
6466         63275 : 35  // end
6467     };
6468
6469     // normalize button clicks
6470     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6471                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6472
6473     Roo.EventObjectImpl = function(e){
6474         if(e){
6475             this.setEvent(e.browserEvent || e);
6476         }
6477     };
6478     Roo.EventObjectImpl.prototype = {
6479         /**
6480          * Used to fix doc tools.
6481          * @scope Roo.EventObject.prototype
6482          */
6483             
6484
6485         
6486         
6487         /** The normal browser event */
6488         browserEvent : null,
6489         /** The button pressed in a mouse event */
6490         button : -1,
6491         /** True if the shift key was down during the event */
6492         shiftKey : false,
6493         /** True if the control key was down during the event */
6494         ctrlKey : false,
6495         /** True if the alt key was down during the event */
6496         altKey : false,
6497
6498         /** Key constant 
6499         * @type Number */
6500         BACKSPACE : 8,
6501         /** Key constant 
6502         * @type Number */
6503         TAB : 9,
6504         /** Key constant 
6505         * @type Number */
6506         RETURN : 13,
6507         /** Key constant 
6508         * @type Number */
6509         ENTER : 13,
6510         /** Key constant 
6511         * @type Number */
6512         SHIFT : 16,
6513         /** Key constant 
6514         * @type Number */
6515         CONTROL : 17,
6516         /** Key constant 
6517         * @type Number */
6518         ESC : 27,
6519         /** Key constant 
6520         * @type Number */
6521         SPACE : 32,
6522         /** Key constant 
6523         * @type Number */
6524         PAGEUP : 33,
6525         /** Key constant 
6526         * @type Number */
6527         PAGEDOWN : 34,
6528         /** Key constant 
6529         * @type Number */
6530         END : 35,
6531         /** Key constant 
6532         * @type Number */
6533         HOME : 36,
6534         /** Key constant 
6535         * @type Number */
6536         LEFT : 37,
6537         /** Key constant 
6538         * @type Number */
6539         UP : 38,
6540         /** Key constant 
6541         * @type Number */
6542         RIGHT : 39,
6543         /** Key constant 
6544         * @type Number */
6545         DOWN : 40,
6546         /** Key constant 
6547         * @type Number */
6548         DELETE : 46,
6549         /** Key constant 
6550         * @type Number */
6551         F5 : 116,
6552
6553            /** @private */
6554         setEvent : function(e){
6555             if(e == this || (e && e.browserEvent)){ // already wrapped
6556                 return e;
6557             }
6558             this.browserEvent = e;
6559             if(e){
6560                 // normalize buttons
6561                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6562                 if(e.type == 'click' && this.button == -1){
6563                     this.button = 0;
6564                 }
6565                 this.type = e.type;
6566                 this.shiftKey = e.shiftKey;
6567                 // mac metaKey behaves like ctrlKey
6568                 this.ctrlKey = e.ctrlKey || e.metaKey;
6569                 this.altKey = e.altKey;
6570                 // in getKey these will be normalized for the mac
6571                 this.keyCode = e.keyCode;
6572                 // keyup warnings on firefox.
6573                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6574                 // cache the target for the delayed and or buffered events
6575                 this.target = E.getTarget(e);
6576                 // same for XY
6577                 this.xy = E.getXY(e);
6578             }else{
6579                 this.button = -1;
6580                 this.shiftKey = false;
6581                 this.ctrlKey = false;
6582                 this.altKey = false;
6583                 this.keyCode = 0;
6584                 this.charCode =0;
6585                 this.target = null;
6586                 this.xy = [0, 0];
6587             }
6588             return this;
6589         },
6590
6591         /**
6592          * Stop the event (preventDefault and stopPropagation)
6593          */
6594         stopEvent : function(){
6595             if(this.browserEvent){
6596                 if(this.browserEvent.type == 'mousedown'){
6597                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6598                 }
6599                 E.stopEvent(this.browserEvent);
6600             }
6601         },
6602
6603         /**
6604          * Prevents the browsers default handling of the event.
6605          */
6606         preventDefault : function(){
6607             if(this.browserEvent){
6608                 E.preventDefault(this.browserEvent);
6609             }
6610         },
6611
6612         /** @private */
6613         isNavKeyPress : function(){
6614             var k = this.keyCode;
6615             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6616             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6617         },
6618
6619         isSpecialKey : function(){
6620             var k = this.keyCode;
6621             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6622             (k == 16) || (k == 17) ||
6623             (k >= 18 && k <= 20) ||
6624             (k >= 33 && k <= 35) ||
6625             (k >= 36 && k <= 39) ||
6626             (k >= 44 && k <= 45);
6627         },
6628         /**
6629          * Cancels bubbling of the event.
6630          */
6631         stopPropagation : function(){
6632             if(this.browserEvent){
6633                 if(this.type == 'mousedown'){
6634                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6635                 }
6636                 E.stopPropagation(this.browserEvent);
6637             }
6638         },
6639
6640         /**
6641          * Gets the key code for the event.
6642          * @return {Number}
6643          */
6644         getCharCode : function(){
6645             return this.charCode || this.keyCode;
6646         },
6647
6648         /**
6649          * Returns a normalized keyCode for the event.
6650          * @return {Number} The key code
6651          */
6652         getKey : function(){
6653             var k = this.keyCode || this.charCode;
6654             return Roo.isSafari ? (safariKeys[k] || k) : k;
6655         },
6656
6657         /**
6658          * Gets the x coordinate of the event.
6659          * @return {Number}
6660          */
6661         getPageX : function(){
6662             return this.xy[0];
6663         },
6664
6665         /**
6666          * Gets the y coordinate of the event.
6667          * @return {Number}
6668          */
6669         getPageY : function(){
6670             return this.xy[1];
6671         },
6672
6673         /**
6674          * Gets the time of the event.
6675          * @return {Number}
6676          */
6677         getTime : function(){
6678             if(this.browserEvent){
6679                 return E.getTime(this.browserEvent);
6680             }
6681             return null;
6682         },
6683
6684         /**
6685          * Gets the page coordinates of the event.
6686          * @return {Array} The xy values like [x, y]
6687          */
6688         getXY : function(){
6689             return this.xy;
6690         },
6691
6692         /**
6693          * Gets the target for the event.
6694          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6695          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6696                 search as a number or element (defaults to 10 || document.body)
6697          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6698          * @return {HTMLelement}
6699          */
6700         getTarget : function(selector, maxDepth, returnEl){
6701             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6702         },
6703         /**
6704          * Gets the related target.
6705          * @return {HTMLElement}
6706          */
6707         getRelatedTarget : function(){
6708             if(this.browserEvent){
6709                 return E.getRelatedTarget(this.browserEvent);
6710             }
6711             return null;
6712         },
6713
6714         /**
6715          * Normalizes mouse wheel delta across browsers
6716          * @return {Number} The delta
6717          */
6718         getWheelDelta : function(){
6719             var e = this.browserEvent;
6720             var delta = 0;
6721             if(e.wheelDelta){ /* IE/Opera. */
6722                 delta = e.wheelDelta/120;
6723             }else if(e.detail){ /* Mozilla case. */
6724                 delta = -e.detail/3;
6725             }
6726             return delta;
6727         },
6728
6729         /**
6730          * Returns true if the control, meta, shift or alt key was pressed during this event.
6731          * @return {Boolean}
6732          */
6733         hasModifier : function(){
6734             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6735         },
6736
6737         /**
6738          * Returns true if the target of this event equals el or is a child of el
6739          * @param {String/HTMLElement/Element} el
6740          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6741          * @return {Boolean}
6742          */
6743         within : function(el, related){
6744             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6745             return t && Roo.fly(el).contains(t);
6746         },
6747
6748         getPoint : function(){
6749             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6750         }
6751     };
6752
6753     return new Roo.EventObjectImpl();
6754 }();
6755             
6756     /*
6757  * Based on:
6758  * Ext JS Library 1.1.1
6759  * Copyright(c) 2006-2007, Ext JS, LLC.
6760  *
6761  * Originally Released Under LGPL - original licence link has changed is not relivant.
6762  *
6763  * Fork - LGPL
6764  * <script type="text/javascript">
6765  */
6766
6767  
6768 // was in Composite Element!??!?!
6769  
6770 (function(){
6771     var D = Roo.lib.Dom;
6772     var E = Roo.lib.Event;
6773     var A = Roo.lib.Anim;
6774
6775     // local style camelizing for speed
6776     var propCache = {};
6777     var camelRe = /(-[a-z])/gi;
6778     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6779     var view = document.defaultView;
6780
6781 /**
6782  * @class Roo.Element
6783  * Represents an Element in the DOM.<br><br>
6784  * Usage:<br>
6785 <pre><code>
6786 var el = Roo.get("my-div");
6787
6788 // or with getEl
6789 var el = getEl("my-div");
6790
6791 // or with a DOM element
6792 var el = Roo.get(myDivElement);
6793 </code></pre>
6794  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6795  * each call instead of constructing a new one.<br><br>
6796  * <b>Animations</b><br />
6797  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6798  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6799 <pre>
6800 Option    Default   Description
6801 --------- --------  ---------------------------------------------
6802 duration  .35       The duration of the animation in seconds
6803 easing    easeOut   The YUI easing method
6804 callback  none      A function to execute when the anim completes
6805 scope     this      The scope (this) of the callback function
6806 </pre>
6807 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6808 * manipulate the animation. Here's an example:
6809 <pre><code>
6810 var el = Roo.get("my-div");
6811
6812 // no animation
6813 el.setWidth(100);
6814
6815 // default animation
6816 el.setWidth(100, true);
6817
6818 // animation with some options set
6819 el.setWidth(100, {
6820     duration: 1,
6821     callback: this.foo,
6822     scope: this
6823 });
6824
6825 // using the "anim" property to get the Anim object
6826 var opt = {
6827     duration: 1,
6828     callback: this.foo,
6829     scope: this
6830 };
6831 el.setWidth(100, opt);
6832 ...
6833 if(opt.anim.isAnimated()){
6834     opt.anim.stop();
6835 }
6836 </code></pre>
6837 * <b> Composite (Collections of) Elements</b><br />
6838  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6839  * @constructor Create a new Element directly.
6840  * @param {String/HTMLElement} element
6841  * @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).
6842  */
6843     Roo.Element = function(element, forceNew){
6844         var dom = typeof element == "string" ?
6845                 document.getElementById(element) : element;
6846         if(!dom){ // invalid id/element
6847             return null;
6848         }
6849         var id = dom.id;
6850         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6851             return Roo.Element.cache[id];
6852         }
6853
6854         /**
6855          * The DOM element
6856          * @type HTMLElement
6857          */
6858         this.dom = dom;
6859
6860         /**
6861          * The DOM element ID
6862          * @type String
6863          */
6864         this.id = id || Roo.id(dom);
6865     };
6866
6867     var El = Roo.Element;
6868
6869     El.prototype = {
6870         /**
6871          * The element's default display mode  (defaults to "")
6872          * @type String
6873          */
6874         originalDisplay : "",
6875
6876         visibilityMode : 1,
6877         /**
6878          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6879          * @type String
6880          */
6881         defaultUnit : "px",
6882         /**
6883          * Sets the element's visibility mode. When setVisible() is called it
6884          * will use this to determine whether to set the visibility or the display property.
6885          * @param visMode Element.VISIBILITY or Element.DISPLAY
6886          * @return {Roo.Element} this
6887          */
6888         setVisibilityMode : function(visMode){
6889             this.visibilityMode = visMode;
6890             return this;
6891         },
6892         /**
6893          * Convenience method for setVisibilityMode(Element.DISPLAY)
6894          * @param {String} display (optional) What to set display to when visible
6895          * @return {Roo.Element} this
6896          */
6897         enableDisplayMode : function(display){
6898             this.setVisibilityMode(El.DISPLAY);
6899             if(typeof display != "undefined") this.originalDisplay = display;
6900             return this;
6901         },
6902
6903         /**
6904          * 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)
6905          * @param {String} selector The simple selector to test
6906          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6907                 search as a number or element (defaults to 10 || document.body)
6908          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6909          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6910          */
6911         findParent : function(simpleSelector, maxDepth, returnEl){
6912             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6913             maxDepth = maxDepth || 50;
6914             if(typeof maxDepth != "number"){
6915                 stopEl = Roo.getDom(maxDepth);
6916                 maxDepth = 10;
6917             }
6918             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6919                 if(dq.is(p, simpleSelector)){
6920                     return returnEl ? Roo.get(p) : p;
6921                 }
6922                 depth++;
6923                 p = p.parentNode;
6924             }
6925             return null;
6926         },
6927
6928
6929         /**
6930          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6931          * @param {String} selector The simple selector to test
6932          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6933                 search as a number or element (defaults to 10 || document.body)
6934          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6935          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6936          */
6937         findParentNode : function(simpleSelector, maxDepth, returnEl){
6938             var p = Roo.fly(this.dom.parentNode, '_internal');
6939             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6940         },
6941
6942         /**
6943          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6944          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6945          * @param {String} selector The simple selector to test
6946          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6947                 search as a number or element (defaults to 10 || document.body)
6948          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6949          */
6950         up : function(simpleSelector, maxDepth){
6951             return this.findParentNode(simpleSelector, maxDepth, true);
6952         },
6953
6954
6955
6956         /**
6957          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6958          * @param {String} selector The simple selector to test
6959          * @return {Boolean} True if this element matches the selector, else false
6960          */
6961         is : function(simpleSelector){
6962             return Roo.DomQuery.is(this.dom, simpleSelector);
6963         },
6964
6965         /**
6966          * Perform animation on this element.
6967          * @param {Object} args The YUI animation control args
6968          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6969          * @param {Function} onComplete (optional) Function to call when animation completes
6970          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6971          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6972          * @return {Roo.Element} this
6973          */
6974         animate : function(args, duration, onComplete, easing, animType){
6975             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6976             return this;
6977         },
6978
6979         /*
6980          * @private Internal animation call
6981          */
6982         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6983             animType = animType || 'run';
6984             opt = opt || {};
6985             var anim = Roo.lib.Anim[animType](
6986                 this.dom, args,
6987                 (opt.duration || defaultDur) || .35,
6988                 (opt.easing || defaultEase) || 'easeOut',
6989                 function(){
6990                     Roo.callback(cb, this);
6991                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6992                 },
6993                 this
6994             );
6995             opt.anim = anim;
6996             return anim;
6997         },
6998
6999         // private legacy anim prep
7000         preanim : function(a, i){
7001             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7002         },
7003
7004         /**
7005          * Removes worthless text nodes
7006          * @param {Boolean} forceReclean (optional) By default the element
7007          * keeps track if it has been cleaned already so
7008          * you can call this over and over. However, if you update the element and
7009          * need to force a reclean, you can pass true.
7010          */
7011         clean : function(forceReclean){
7012             if(this.isCleaned && forceReclean !== true){
7013                 return this;
7014             }
7015             var ns = /\S/;
7016             var d = this.dom, n = d.firstChild, ni = -1;
7017             while(n){
7018                 var nx = n.nextSibling;
7019                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7020                     d.removeChild(n);
7021                 }else{
7022                     n.nodeIndex = ++ni;
7023                 }
7024                 n = nx;
7025             }
7026             this.isCleaned = true;
7027             return this;
7028         },
7029
7030         // private
7031         calcOffsetsTo : function(el){
7032             el = Roo.get(el);
7033             var d = el.dom;
7034             var restorePos = false;
7035             if(el.getStyle('position') == 'static'){
7036                 el.position('relative');
7037                 restorePos = true;
7038             }
7039             var x = 0, y =0;
7040             var op = this.dom;
7041             while(op && op != d && op.tagName != 'HTML'){
7042                 x+= op.offsetLeft;
7043                 y+= op.offsetTop;
7044                 op = op.offsetParent;
7045             }
7046             if(restorePos){
7047                 el.position('static');
7048             }
7049             return [x, y];
7050         },
7051
7052         /**
7053          * Scrolls this element into view within the passed container.
7054          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7055          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7056          * @return {Roo.Element} this
7057          */
7058         scrollIntoView : function(container, hscroll){
7059             var c = Roo.getDom(container) || document.body;
7060             var el = this.dom;
7061
7062             var o = this.calcOffsetsTo(c),
7063                 l = o[0],
7064                 t = o[1],
7065                 b = t+el.offsetHeight,
7066                 r = l+el.offsetWidth;
7067
7068             var ch = c.clientHeight;
7069             var ct = parseInt(c.scrollTop, 10);
7070             var cl = parseInt(c.scrollLeft, 10);
7071             var cb = ct + ch;
7072             var cr = cl + c.clientWidth;
7073
7074             if(t < ct){
7075                 c.scrollTop = t;
7076             }else if(b > cb){
7077                 c.scrollTop = b-ch;
7078             }
7079
7080             if(hscroll !== false){
7081                 if(l < cl){
7082                     c.scrollLeft = l;
7083                 }else if(r > cr){
7084                     c.scrollLeft = r-c.clientWidth;
7085                 }
7086             }
7087             return this;
7088         },
7089
7090         // private
7091         scrollChildIntoView : function(child, hscroll){
7092             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7093         },
7094
7095         /**
7096          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7097          * the new height may not be available immediately.
7098          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7099          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7100          * @param {Function} onComplete (optional) Function to call when animation completes
7101          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7102          * @return {Roo.Element} this
7103          */
7104         autoHeight : function(animate, duration, onComplete, easing){
7105             var oldHeight = this.getHeight();
7106             this.clip();
7107             this.setHeight(1); // force clipping
7108             setTimeout(function(){
7109                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7110                 if(!animate){
7111                     this.setHeight(height);
7112                     this.unclip();
7113                     if(typeof onComplete == "function"){
7114                         onComplete();
7115                     }
7116                 }else{
7117                     this.setHeight(oldHeight); // restore original height
7118                     this.setHeight(height, animate, duration, function(){
7119                         this.unclip();
7120                         if(typeof onComplete == "function") onComplete();
7121                     }.createDelegate(this), easing);
7122                 }
7123             }.createDelegate(this), 0);
7124             return this;
7125         },
7126
7127         /**
7128          * Returns true if this element is an ancestor of the passed element
7129          * @param {HTMLElement/String} el The element to check
7130          * @return {Boolean} True if this element is an ancestor of el, else false
7131          */
7132         contains : function(el){
7133             if(!el){return false;}
7134             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7135         },
7136
7137         /**
7138          * Checks whether the element is currently visible using both visibility and display properties.
7139          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7140          * @return {Boolean} True if the element is currently visible, else false
7141          */
7142         isVisible : function(deep) {
7143             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7144             if(deep !== true || !vis){
7145                 return vis;
7146             }
7147             var p = this.dom.parentNode;
7148             while(p && p.tagName.toLowerCase() != "body"){
7149                 if(!Roo.fly(p, '_isVisible').isVisible()){
7150                     return false;
7151                 }
7152                 p = p.parentNode;
7153             }
7154             return true;
7155         },
7156
7157         /**
7158          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7159          * @param {String} selector The CSS selector
7160          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7161          * @return {CompositeElement/CompositeElementLite} The composite element
7162          */
7163         select : function(selector, unique){
7164             return El.select(selector, unique, this.dom);
7165         },
7166
7167         /**
7168          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7169          * @param {String} selector The CSS selector
7170          * @return {Array} An array of the matched nodes
7171          */
7172         query : function(selector, unique){
7173             return Roo.DomQuery.select(selector, this.dom);
7174         },
7175
7176         /**
7177          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7178          * @param {String} selector The CSS selector
7179          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7180          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7181          */
7182         child : function(selector, returnDom){
7183             var n = Roo.DomQuery.selectNode(selector, this.dom);
7184             return returnDom ? n : Roo.get(n);
7185         },
7186
7187         /**
7188          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7189          * @param {String} selector The CSS selector
7190          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7191          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7192          */
7193         down : function(selector, returnDom){
7194             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7195             return returnDom ? n : Roo.get(n);
7196         },
7197
7198         /**
7199          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7200          * @param {String} group The group the DD object is member of
7201          * @param {Object} config The DD config object
7202          * @param {Object} overrides An object containing methods to override/implement on the DD object
7203          * @return {Roo.dd.DD} The DD object
7204          */
7205         initDD : function(group, config, overrides){
7206             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7207             return Roo.apply(dd, overrides);
7208         },
7209
7210         /**
7211          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7212          * @param {String} group The group the DDProxy object is member of
7213          * @param {Object} config The DDProxy config object
7214          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7215          * @return {Roo.dd.DDProxy} The DDProxy object
7216          */
7217         initDDProxy : function(group, config, overrides){
7218             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7219             return Roo.apply(dd, overrides);
7220         },
7221
7222         /**
7223          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7224          * @param {String} group The group the DDTarget object is member of
7225          * @param {Object} config The DDTarget config object
7226          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7227          * @return {Roo.dd.DDTarget} The DDTarget object
7228          */
7229         initDDTarget : function(group, config, overrides){
7230             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7231             return Roo.apply(dd, overrides);
7232         },
7233
7234         /**
7235          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7236          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7237          * @param {Boolean} visible Whether the element is visible
7238          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7239          * @return {Roo.Element} this
7240          */
7241          setVisible : function(visible, animate){
7242             if(!animate || !A){
7243                 if(this.visibilityMode == El.DISPLAY){
7244                     this.setDisplayed(visible);
7245                 }else{
7246                     this.fixDisplay();
7247                     this.dom.style.visibility = visible ? "visible" : "hidden";
7248                 }
7249             }else{
7250                 // closure for composites
7251                 var dom = this.dom;
7252                 var visMode = this.visibilityMode;
7253                 if(visible){
7254                     this.setOpacity(.01);
7255                     this.setVisible(true);
7256                 }
7257                 this.anim({opacity: { to: (visible?1:0) }},
7258                       this.preanim(arguments, 1),
7259                       null, .35, 'easeIn', function(){
7260                          if(!visible){
7261                              if(visMode == El.DISPLAY){
7262                                  dom.style.display = "none";
7263                              }else{
7264                                  dom.style.visibility = "hidden";
7265                              }
7266                              Roo.get(dom).setOpacity(1);
7267                          }
7268                      });
7269             }
7270             return this;
7271         },
7272
7273         /**
7274          * Returns true if display is not "none"
7275          * @return {Boolean}
7276          */
7277         isDisplayed : function() {
7278             return this.getStyle("display") != "none";
7279         },
7280
7281         /**
7282          * Toggles the element's visibility or display, depending on visibility mode.
7283          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7284          * @return {Roo.Element} this
7285          */
7286         toggle : function(animate){
7287             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7288             return this;
7289         },
7290
7291         /**
7292          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7293          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7294          * @return {Roo.Element} this
7295          */
7296         setDisplayed : function(value) {
7297             if(typeof value == "boolean"){
7298                value = value ? this.originalDisplay : "none";
7299             }
7300             this.setStyle("display", value);
7301             return this;
7302         },
7303
7304         /**
7305          * Tries to focus the element. Any exceptions are caught and ignored.
7306          * @return {Roo.Element} this
7307          */
7308         focus : function() {
7309             try{
7310                 this.dom.focus();
7311             }catch(e){}
7312             return this;
7313         },
7314
7315         /**
7316          * Tries to blur the element. Any exceptions are caught and ignored.
7317          * @return {Roo.Element} this
7318          */
7319         blur : function() {
7320             try{
7321                 this.dom.blur();
7322             }catch(e){}
7323             return this;
7324         },
7325
7326         /**
7327          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7328          * @param {String/Array} className The CSS class to add, or an array of classes
7329          * @return {Roo.Element} this
7330          */
7331         addClass : function(className){
7332             if(className instanceof Array){
7333                 for(var i = 0, len = className.length; i < len; i++) {
7334                     this.addClass(className[i]);
7335                 }
7336             }else{
7337                 if(className && !this.hasClass(className)){
7338                     this.dom.className = this.dom.className + " " + className;
7339                 }
7340             }
7341             return this;
7342         },
7343
7344         /**
7345          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7346          * @param {String/Array} className The CSS class to add, or an array of classes
7347          * @return {Roo.Element} this
7348          */
7349         radioClass : function(className){
7350             var siblings = this.dom.parentNode.childNodes;
7351             for(var i = 0; i < siblings.length; i++) {
7352                 var s = siblings[i];
7353                 if(s.nodeType == 1){
7354                     Roo.get(s).removeClass(className);
7355                 }
7356             }
7357             this.addClass(className);
7358             return this;
7359         },
7360
7361         /**
7362          * Removes one or more CSS classes from the element.
7363          * @param {String/Array} className The CSS class to remove, or an array of classes
7364          * @return {Roo.Element} this
7365          */
7366         removeClass : function(className){
7367             if(!className || !this.dom.className){
7368                 return this;
7369             }
7370             if(className instanceof Array){
7371                 for(var i = 0, len = className.length; i < len; i++) {
7372                     this.removeClass(className[i]);
7373                 }
7374             }else{
7375                 if(this.hasClass(className)){
7376                     var re = this.classReCache[className];
7377                     if (!re) {
7378                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7379                        this.classReCache[className] = re;
7380                     }
7381                     this.dom.className =
7382                         this.dom.className.replace(re, " ");
7383                 }
7384             }
7385             return this;
7386         },
7387
7388         // private
7389         classReCache: {},
7390
7391         /**
7392          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7393          * @param {String} className The CSS class to toggle
7394          * @return {Roo.Element} this
7395          */
7396         toggleClass : function(className){
7397             if(this.hasClass(className)){
7398                 this.removeClass(className);
7399             }else{
7400                 this.addClass(className);
7401             }
7402             return this;
7403         },
7404
7405         /**
7406          * Checks if the specified CSS class exists on this element's DOM node.
7407          * @param {String} className The CSS class to check for
7408          * @return {Boolean} True if the class exists, else false
7409          */
7410         hasClass : function(className){
7411             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7412         },
7413
7414         /**
7415          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7416          * @param {String} oldClassName The CSS class to replace
7417          * @param {String} newClassName The replacement CSS class
7418          * @return {Roo.Element} this
7419          */
7420         replaceClass : function(oldClassName, newClassName){
7421             this.removeClass(oldClassName);
7422             this.addClass(newClassName);
7423             return this;
7424         },
7425
7426         /**
7427          * Returns an object with properties matching the styles requested.
7428          * For example, el.getStyles('color', 'font-size', 'width') might return
7429          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7430          * @param {String} style1 A style name
7431          * @param {String} style2 A style name
7432          * @param {String} etc.
7433          * @return {Object} The style object
7434          */
7435         getStyles : function(){
7436             var a = arguments, len = a.length, r = {};
7437             for(var i = 0; i < len; i++){
7438                 r[a[i]] = this.getStyle(a[i]);
7439             }
7440             return r;
7441         },
7442
7443         /**
7444          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7445          * @param {String} property The style property whose value is returned.
7446          * @return {String} The current value of the style property for this element.
7447          */
7448         getStyle : function(){
7449             return view && view.getComputedStyle ?
7450                 function(prop){
7451                     var el = this.dom, v, cs, camel;
7452                     if(prop == 'float'){
7453                         prop = "cssFloat";
7454                     }
7455                     if(el.style && (v = el.style[prop])){
7456                         return v;
7457                     }
7458                     if(cs = view.getComputedStyle(el, "")){
7459                         if(!(camel = propCache[prop])){
7460                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7461                         }
7462                         return cs[camel];
7463                     }
7464                     return null;
7465                 } :
7466                 function(prop){
7467                     var el = this.dom, v, cs, camel;
7468                     if(prop == 'opacity'){
7469                         if(typeof el.style.filter == 'string'){
7470                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7471                             if(m){
7472                                 var fv = parseFloat(m[1]);
7473                                 if(!isNaN(fv)){
7474                                     return fv ? fv / 100 : 0;
7475                                 }
7476                             }
7477                         }
7478                         return 1;
7479                     }else if(prop == 'float'){
7480                         prop = "styleFloat";
7481                     }
7482                     if(!(camel = propCache[prop])){
7483                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7484                     }
7485                     if(v = el.style[camel]){
7486                         return v;
7487                     }
7488                     if(cs = el.currentStyle){
7489                         return cs[camel];
7490                     }
7491                     return null;
7492                 };
7493         }(),
7494
7495         /**
7496          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7497          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7498          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7499          * @return {Roo.Element} this
7500          */
7501         setStyle : function(prop, value){
7502             if(typeof prop == "string"){
7503                 
7504                 if (prop == 'float') {
7505                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7506                     return this;
7507                 }
7508                 
7509                 var camel;
7510                 if(!(camel = propCache[prop])){
7511                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7512                 }
7513                 
7514                 if(camel == 'opacity') {
7515                     this.setOpacity(value);
7516                 }else{
7517                     this.dom.style[camel] = value;
7518                 }
7519             }else{
7520                 for(var style in prop){
7521                     if(typeof prop[style] != "function"){
7522                        this.setStyle(style, prop[style]);
7523                     }
7524                 }
7525             }
7526             return this;
7527         },
7528
7529         /**
7530          * More flexible version of {@link #setStyle} for setting style properties.
7531          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7532          * a function which returns such a specification.
7533          * @return {Roo.Element} this
7534          */
7535         applyStyles : function(style){
7536             Roo.DomHelper.applyStyles(this.dom, style);
7537             return this;
7538         },
7539
7540         /**
7541           * 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).
7542           * @return {Number} The X position of the element
7543           */
7544         getX : function(){
7545             return D.getX(this.dom);
7546         },
7547
7548         /**
7549           * 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).
7550           * @return {Number} The Y position of the element
7551           */
7552         getY : function(){
7553             return D.getY(this.dom);
7554         },
7555
7556         /**
7557           * 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).
7558           * @return {Array} The XY position of the element
7559           */
7560         getXY : function(){
7561             return D.getXY(this.dom);
7562         },
7563
7564         /**
7565          * 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).
7566          * @param {Number} The X 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         setX : function(x, animate){
7571             if(!animate || !A){
7572                 D.setX(this.dom, x);
7573             }else{
7574                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7575             }
7576             return this;
7577         },
7578
7579         /**
7580          * 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).
7581          * @param {Number} The Y position of the element
7582          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7583          * @return {Roo.Element} this
7584          */
7585         setY : function(y, animate){
7586             if(!animate || !A){
7587                 D.setY(this.dom, y);
7588             }else{
7589                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7590             }
7591             return this;
7592         },
7593
7594         /**
7595          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7596          * @param {String} left The left CSS property value
7597          * @return {Roo.Element} this
7598          */
7599         setLeft : function(left){
7600             this.setStyle("left", this.addUnits(left));
7601             return this;
7602         },
7603
7604         /**
7605          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7606          * @param {String} top The top CSS property value
7607          * @return {Roo.Element} this
7608          */
7609         setTop : function(top){
7610             this.setStyle("top", this.addUnits(top));
7611             return this;
7612         },
7613
7614         /**
7615          * Sets the element's CSS right style.
7616          * @param {String} right The right CSS property value
7617          * @return {Roo.Element} this
7618          */
7619         setRight : function(right){
7620             this.setStyle("right", this.addUnits(right));
7621             return this;
7622         },
7623
7624         /**
7625          * Sets the element's CSS bottom style.
7626          * @param {String} bottom The bottom CSS property value
7627          * @return {Roo.Element} this
7628          */
7629         setBottom : function(bottom){
7630             this.setStyle("bottom", this.addUnits(bottom));
7631             return this;
7632         },
7633
7634         /**
7635          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7636          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7637          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7638          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7639          * @return {Roo.Element} this
7640          */
7641         setXY : function(pos, animate){
7642             if(!animate || !A){
7643                 D.setXY(this.dom, pos);
7644             }else{
7645                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7646             }
7647             return this;
7648         },
7649
7650         /**
7651          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7652          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7653          * @param {Number} x X value for new position (coordinates are page-based)
7654          * @param {Number} y Y value for new position (coordinates are page-based)
7655          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7656          * @return {Roo.Element} this
7657          */
7658         setLocation : function(x, y, animate){
7659             this.setXY([x, y], this.preanim(arguments, 2));
7660             return this;
7661         },
7662
7663         /**
7664          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7665          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7666          * @param {Number} x X value for new position (coordinates are page-based)
7667          * @param {Number} y Y value for new position (coordinates are page-based)
7668          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7669          * @return {Roo.Element} this
7670          */
7671         moveTo : function(x, y, animate){
7672             this.setXY([x, y], this.preanim(arguments, 2));
7673             return this;
7674         },
7675
7676         /**
7677          * Returns the region of the given element.
7678          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7679          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7680          */
7681         getRegion : function(){
7682             return D.getRegion(this.dom);
7683         },
7684
7685         /**
7686          * Returns the offset height of the element
7687          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7688          * @return {Number} The element's height
7689          */
7690         getHeight : function(contentHeight){
7691             var h = this.dom.offsetHeight || 0;
7692             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7693         },
7694
7695         /**
7696          * Returns the offset width of the element
7697          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7698          * @return {Number} The element's width
7699          */
7700         getWidth : function(contentWidth){
7701             var w = this.dom.offsetWidth || 0;
7702             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7703         },
7704
7705         /**
7706          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7707          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7708          * if a height has not been set using CSS.
7709          * @return {Number}
7710          */
7711         getComputedHeight : function(){
7712             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7713             if(!h){
7714                 h = parseInt(this.getStyle('height'), 10) || 0;
7715                 if(!this.isBorderBox()){
7716                     h += this.getFrameWidth('tb');
7717                 }
7718             }
7719             return h;
7720         },
7721
7722         /**
7723          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7724          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7725          * if a width has not been set using CSS.
7726          * @return {Number}
7727          */
7728         getComputedWidth : function(){
7729             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7730             if(!w){
7731                 w = parseInt(this.getStyle('width'), 10) || 0;
7732                 if(!this.isBorderBox()){
7733                     w += this.getFrameWidth('lr');
7734                 }
7735             }
7736             return w;
7737         },
7738
7739         /**
7740          * Returns the size of the element.
7741          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7742          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7743          */
7744         getSize : function(contentSize){
7745             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7746         },
7747
7748         /**
7749          * Returns the width and height of the viewport.
7750          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7751          */
7752         getViewSize : function(){
7753             var d = this.dom, doc = document, aw = 0, ah = 0;
7754             if(d == doc || d == doc.body){
7755                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7756             }else{
7757                 return {
7758                     width : d.clientWidth,
7759                     height: d.clientHeight
7760                 };
7761             }
7762         },
7763
7764         /**
7765          * Returns the value of the "value" attribute
7766          * @param {Boolean} asNumber true to parse the value as a number
7767          * @return {String/Number}
7768          */
7769         getValue : function(asNumber){
7770             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7771         },
7772
7773         // private
7774         adjustWidth : function(width){
7775             if(typeof width == "number"){
7776                 if(this.autoBoxAdjust && !this.isBorderBox()){
7777                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7778                 }
7779                 if(width < 0){
7780                     width = 0;
7781                 }
7782             }
7783             return width;
7784         },
7785
7786         // private
7787         adjustHeight : function(height){
7788             if(typeof height == "number"){
7789                if(this.autoBoxAdjust && !this.isBorderBox()){
7790                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7791                }
7792                if(height < 0){
7793                    height = 0;
7794                }
7795             }
7796             return height;
7797         },
7798
7799         /**
7800          * Set the width of the element
7801          * @param {Number} width The new width
7802          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7803          * @return {Roo.Element} this
7804          */
7805         setWidth : function(width, animate){
7806             width = this.adjustWidth(width);
7807             if(!animate || !A){
7808                 this.dom.style.width = this.addUnits(width);
7809             }else{
7810                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7811             }
7812             return this;
7813         },
7814
7815         /**
7816          * Set the height of the element
7817          * @param {Number} height The new height
7818          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7819          * @return {Roo.Element} this
7820          */
7821          setHeight : function(height, animate){
7822             height = this.adjustHeight(height);
7823             if(!animate || !A){
7824                 this.dom.style.height = this.addUnits(height);
7825             }else{
7826                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7827             }
7828             return this;
7829         },
7830
7831         /**
7832          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7833          * @param {Number} width The new width
7834          * @param {Number} height The new height
7835          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7836          * @return {Roo.Element} this
7837          */
7838          setSize : function(width, height, animate){
7839             if(typeof width == "object"){ // in case of object from getSize()
7840                 height = width.height; width = width.width;
7841             }
7842             width = this.adjustWidth(width); height = this.adjustHeight(height);
7843             if(!animate || !A){
7844                 this.dom.style.width = this.addUnits(width);
7845                 this.dom.style.height = this.addUnits(height);
7846             }else{
7847                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7848             }
7849             return this;
7850         },
7851
7852         /**
7853          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7854          * @param {Number} x X value for new position (coordinates are page-based)
7855          * @param {Number} y Y value for new position (coordinates are page-based)
7856          * @param {Number} width The new width
7857          * @param {Number} height The new height
7858          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7859          * @return {Roo.Element} this
7860          */
7861         setBounds : function(x, y, width, height, animate){
7862             if(!animate || !A){
7863                 this.setSize(width, height);
7864                 this.setLocation(x, y);
7865             }else{
7866                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7867                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7868                               this.preanim(arguments, 4), 'motion');
7869             }
7870             return this;
7871         },
7872
7873         /**
7874          * 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.
7875          * @param {Roo.lib.Region} region The region to fill
7876          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7877          * @return {Roo.Element} this
7878          */
7879         setRegion : function(region, animate){
7880             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7881             return this;
7882         },
7883
7884         /**
7885          * Appends an event handler
7886          *
7887          * @param {String}   eventName     The type of event to append
7888          * @param {Function} fn        The method the event invokes
7889          * @param {Object} scope       (optional) The scope (this object) of the fn
7890          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7891          */
7892         addListener : function(eventName, fn, scope, options){
7893             if (this.dom) {
7894                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7895             }
7896         },
7897
7898         /**
7899          * Removes an event handler from this element
7900          * @param {String} eventName the type of event to remove
7901          * @param {Function} fn the method the event invokes
7902          * @return {Roo.Element} this
7903          */
7904         removeListener : function(eventName, fn){
7905             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7906             return this;
7907         },
7908
7909         /**
7910          * Removes all previous added listeners from this element
7911          * @return {Roo.Element} this
7912          */
7913         removeAllListeners : function(){
7914             E.purgeElement(this.dom);
7915             return this;
7916         },
7917
7918         relayEvent : function(eventName, observable){
7919             this.on(eventName, function(e){
7920                 observable.fireEvent(eventName, e);
7921             });
7922         },
7923
7924         /**
7925          * Set the opacity of the element
7926          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7927          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7928          * @return {Roo.Element} this
7929          */
7930          setOpacity : function(opacity, animate){
7931             if(!animate || !A){
7932                 var s = this.dom.style;
7933                 if(Roo.isIE){
7934                     s.zoom = 1;
7935                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7936                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7937                 }else{
7938                     s.opacity = opacity;
7939                 }
7940             }else{
7941                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7942             }
7943             return this;
7944         },
7945
7946         /**
7947          * Gets the left X coordinate
7948          * @param {Boolean} local True to get the local css position instead of page coordinate
7949          * @return {Number}
7950          */
7951         getLeft : function(local){
7952             if(!local){
7953                 return this.getX();
7954             }else{
7955                 return parseInt(this.getStyle("left"), 10) || 0;
7956             }
7957         },
7958
7959         /**
7960          * Gets the right X coordinate of the element (element X position + element width)
7961          * @param {Boolean} local True to get the local css position instead of page coordinate
7962          * @return {Number}
7963          */
7964         getRight : function(local){
7965             if(!local){
7966                 return this.getX() + this.getWidth();
7967             }else{
7968                 return (this.getLeft(true) + this.getWidth()) || 0;
7969             }
7970         },
7971
7972         /**
7973          * Gets the top Y coordinate
7974          * @param {Boolean} local True to get the local css position instead of page coordinate
7975          * @return {Number}
7976          */
7977         getTop : function(local) {
7978             if(!local){
7979                 return this.getY();
7980             }else{
7981                 return parseInt(this.getStyle("top"), 10) || 0;
7982             }
7983         },
7984
7985         /**
7986          * Gets the bottom Y coordinate of the element (element Y position + element height)
7987          * @param {Boolean} local True to get the local css position instead of page coordinate
7988          * @return {Number}
7989          */
7990         getBottom : function(local){
7991             if(!local){
7992                 return this.getY() + this.getHeight();
7993             }else{
7994                 return (this.getTop(true) + this.getHeight()) || 0;
7995             }
7996         },
7997
7998         /**
7999         * Initializes positioning on this element. If a desired position is not passed, it will make the
8000         * the element positioned relative IF it is not already positioned.
8001         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8002         * @param {Number} zIndex (optional) The zIndex to apply
8003         * @param {Number} x (optional) Set the page X position
8004         * @param {Number} y (optional) Set the page Y position
8005         */
8006         position : function(pos, zIndex, x, y){
8007             if(!pos){
8008                if(this.getStyle('position') == 'static'){
8009                    this.setStyle('position', 'relative');
8010                }
8011             }else{
8012                 this.setStyle("position", pos);
8013             }
8014             if(zIndex){
8015                 this.setStyle("z-index", zIndex);
8016             }
8017             if(x !== undefined && y !== undefined){
8018                 this.setXY([x, y]);
8019             }else if(x !== undefined){
8020                 this.setX(x);
8021             }else if(y !== undefined){
8022                 this.setY(y);
8023             }
8024         },
8025
8026         /**
8027         * Clear positioning back to the default when the document was loaded
8028         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8029         * @return {Roo.Element} this
8030          */
8031         clearPositioning : function(value){
8032             value = value ||'';
8033             this.setStyle({
8034                 "left": value,
8035                 "right": value,
8036                 "top": value,
8037                 "bottom": value,
8038                 "z-index": "",
8039                 "position" : "static"
8040             });
8041             return this;
8042         },
8043
8044         /**
8045         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8046         * snapshot before performing an update and then restoring the element.
8047         * @return {Object}
8048         */
8049         getPositioning : function(){
8050             var l = this.getStyle("left");
8051             var t = this.getStyle("top");
8052             return {
8053                 "position" : this.getStyle("position"),
8054                 "left" : l,
8055                 "right" : l ? "" : this.getStyle("right"),
8056                 "top" : t,
8057                 "bottom" : t ? "" : this.getStyle("bottom"),
8058                 "z-index" : this.getStyle("z-index")
8059             };
8060         },
8061
8062         /**
8063          * Gets the width of the border(s) for the specified side(s)
8064          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8065          * passing lr would get the border (l)eft width + the border (r)ight width.
8066          * @return {Number} The width of the sides passed added together
8067          */
8068         getBorderWidth : function(side){
8069             return this.addStyles(side, El.borders);
8070         },
8071
8072         /**
8073          * Gets the width of the padding(s) for the specified side(s)
8074          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8075          * passing lr would get the padding (l)eft + the padding (r)ight.
8076          * @return {Number} The padding of the sides passed added together
8077          */
8078         getPadding : function(side){
8079             return this.addStyles(side, El.paddings);
8080         },
8081
8082         /**
8083         * Set positioning with an object returned by getPositioning().
8084         * @param {Object} posCfg
8085         * @return {Roo.Element} this
8086          */
8087         setPositioning : function(pc){
8088             this.applyStyles(pc);
8089             if(pc.right == "auto"){
8090                 this.dom.style.right = "";
8091             }
8092             if(pc.bottom == "auto"){
8093                 this.dom.style.bottom = "";
8094             }
8095             return this;
8096         },
8097
8098         // private
8099         fixDisplay : function(){
8100             if(this.getStyle("display") == "none"){
8101                 this.setStyle("visibility", "hidden");
8102                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8103                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8104                     this.setStyle("display", "block");
8105                 }
8106             }
8107         },
8108
8109         /**
8110          * Quick set left and top adding default units
8111          * @param {String} left The left CSS property value
8112          * @param {String} top The top CSS property value
8113          * @return {Roo.Element} this
8114          */
8115          setLeftTop : function(left, top){
8116             this.dom.style.left = this.addUnits(left);
8117             this.dom.style.top = this.addUnits(top);
8118             return this;
8119         },
8120
8121         /**
8122          * Move this element relative to its current position.
8123          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8124          * @param {Number} distance How far to move the element in pixels
8125          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8126          * @return {Roo.Element} this
8127          */
8128          move : function(direction, distance, animate){
8129             var xy = this.getXY();
8130             direction = direction.toLowerCase();
8131             switch(direction){
8132                 case "l":
8133                 case "left":
8134                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8135                     break;
8136                case "r":
8137                case "right":
8138                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8139                     break;
8140                case "t":
8141                case "top":
8142                case "up":
8143                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8144                     break;
8145                case "b":
8146                case "bottom":
8147                case "down":
8148                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8149                     break;
8150             }
8151             return this;
8152         },
8153
8154         /**
8155          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8156          * @return {Roo.Element} this
8157          */
8158         clip : function(){
8159             if(!this.isClipped){
8160                this.isClipped = true;
8161                this.originalClip = {
8162                    "o": this.getStyle("overflow"),
8163                    "x": this.getStyle("overflow-x"),
8164                    "y": this.getStyle("overflow-y")
8165                };
8166                this.setStyle("overflow", "hidden");
8167                this.setStyle("overflow-x", "hidden");
8168                this.setStyle("overflow-y", "hidden");
8169             }
8170             return this;
8171         },
8172
8173         /**
8174          *  Return clipping (overflow) to original clipping before clip() was called
8175          * @return {Roo.Element} this
8176          */
8177         unclip : function(){
8178             if(this.isClipped){
8179                 this.isClipped = false;
8180                 var o = this.originalClip;
8181                 if(o.o){this.setStyle("overflow", o.o);}
8182                 if(o.x){this.setStyle("overflow-x", o.x);}
8183                 if(o.y){this.setStyle("overflow-y", o.y);}
8184             }
8185             return this;
8186         },
8187
8188
8189         /**
8190          * Gets the x,y coordinates specified by the anchor position on the element.
8191          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8192          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8193          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8194          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8195          * @return {Array} [x, y] An array containing the element's x and y coordinates
8196          */
8197         getAnchorXY : function(anchor, local, s){
8198             //Passing a different size is useful for pre-calculating anchors,
8199             //especially for anchored animations that change the el size.
8200
8201             var w, h, vp = false;
8202             if(!s){
8203                 var d = this.dom;
8204                 if(d == document.body || d == document){
8205                     vp = true;
8206                     w = D.getViewWidth(); h = D.getViewHeight();
8207                 }else{
8208                     w = this.getWidth(); h = this.getHeight();
8209                 }
8210             }else{
8211                 w = s.width;  h = s.height;
8212             }
8213             var x = 0, y = 0, r = Math.round;
8214             switch((anchor || "tl").toLowerCase()){
8215                 case "c":
8216                     x = r(w*.5);
8217                     y = r(h*.5);
8218                 break;
8219                 case "t":
8220                     x = r(w*.5);
8221                     y = 0;
8222                 break;
8223                 case "l":
8224                     x = 0;
8225                     y = r(h*.5);
8226                 break;
8227                 case "r":
8228                     x = w;
8229                     y = r(h*.5);
8230                 break;
8231                 case "b":
8232                     x = r(w*.5);
8233                     y = h;
8234                 break;
8235                 case "tl":
8236                     x = 0;
8237                     y = 0;
8238                 break;
8239                 case "bl":
8240                     x = 0;
8241                     y = h;
8242                 break;
8243                 case "br":
8244                     x = w;
8245                     y = h;
8246                 break;
8247                 case "tr":
8248                     x = w;
8249                     y = 0;
8250                 break;
8251             }
8252             if(local === true){
8253                 return [x, y];
8254             }
8255             if(vp){
8256                 var sc = this.getScroll();
8257                 return [x + sc.left, y + sc.top];
8258             }
8259             //Add the element's offset xy
8260             var o = this.getXY();
8261             return [x+o[0], y+o[1]];
8262         },
8263
8264         /**
8265          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8266          * supported position values.
8267          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8268          * @param {String} position The position to align to.
8269          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8270          * @return {Array} [x, y]
8271          */
8272         getAlignToXY : function(el, p, o){
8273             el = Roo.get(el);
8274             var d = this.dom;
8275             if(!el.dom){
8276                 throw "Element.alignTo with an element that doesn't exist";
8277             }
8278             var c = false; //constrain to viewport
8279             var p1 = "", p2 = "";
8280             o = o || [0,0];
8281
8282             if(!p){
8283                 p = "tl-bl";
8284             }else if(p == "?"){
8285                 p = "tl-bl?";
8286             }else if(p.indexOf("-") == -1){
8287                 p = "tl-" + p;
8288             }
8289             p = p.toLowerCase();
8290             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8291             if(!m){
8292                throw "Element.alignTo with an invalid alignment " + p;
8293             }
8294             p1 = m[1]; p2 = m[2]; c = !!m[3];
8295
8296             //Subtract the aligned el's internal xy from the target's offset xy
8297             //plus custom offset to get the aligned el's new offset xy
8298             var a1 = this.getAnchorXY(p1, true);
8299             var a2 = el.getAnchorXY(p2, false);
8300             var x = a2[0] - a1[0] + o[0];
8301             var y = a2[1] - a1[1] + o[1];
8302             if(c){
8303                 //constrain the aligned el to viewport if necessary
8304                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8305                 // 5px of margin for ie
8306                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8307
8308                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8309                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8310                 //otherwise swap the aligned el to the opposite border of the target.
8311                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8312                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8313                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8314                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8315
8316                var doc = document;
8317                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8318                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8319
8320                if((x+w) > dw + scrollX){
8321                     x = swapX ? r.left-w : dw+scrollX-w;
8322                 }
8323                if(x < scrollX){
8324                    x = swapX ? r.right : scrollX;
8325                }
8326                if((y+h) > dh + scrollY){
8327                     y = swapY ? r.top-h : dh+scrollY-h;
8328                 }
8329                if (y < scrollY){
8330                    y = swapY ? r.bottom : scrollY;
8331                }
8332             }
8333             return [x,y];
8334         },
8335
8336         // private
8337         getConstrainToXY : function(){
8338             var os = {top:0, left:0, bottom:0, right: 0};
8339
8340             return function(el, local, offsets, proposedXY){
8341                 el = Roo.get(el);
8342                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8343
8344                 var vw, vh, vx = 0, vy = 0;
8345                 if(el.dom == document.body || el.dom == document){
8346                     vw = Roo.lib.Dom.getViewWidth();
8347                     vh = Roo.lib.Dom.getViewHeight();
8348                 }else{
8349                     vw = el.dom.clientWidth;
8350                     vh = el.dom.clientHeight;
8351                     if(!local){
8352                         var vxy = el.getXY();
8353                         vx = vxy[0];
8354                         vy = vxy[1];
8355                     }
8356                 }
8357
8358                 var s = el.getScroll();
8359
8360                 vx += offsets.left + s.left;
8361                 vy += offsets.top + s.top;
8362
8363                 vw -= offsets.right;
8364                 vh -= offsets.bottom;
8365
8366                 var vr = vx+vw;
8367                 var vb = vy+vh;
8368
8369                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8370                 var x = xy[0], y = xy[1];
8371                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8372
8373                 // only move it if it needs it
8374                 var moved = false;
8375
8376                 // first validate right/bottom
8377                 if((x + w) > vr){
8378                     x = vr - w;
8379                     moved = true;
8380                 }
8381                 if((y + h) > vb){
8382                     y = vb - h;
8383                     moved = true;
8384                 }
8385                 // then make sure top/left isn't negative
8386                 if(x < vx){
8387                     x = vx;
8388                     moved = true;
8389                 }
8390                 if(y < vy){
8391                     y = vy;
8392                     moved = true;
8393                 }
8394                 return moved ? [x, y] : false;
8395             };
8396         }(),
8397
8398         // private
8399         adjustForConstraints : function(xy, parent, offsets){
8400             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8401         },
8402
8403         /**
8404          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8405          * document it aligns it to the viewport.
8406          * The position parameter is optional, and can be specified in any one of the following formats:
8407          * <ul>
8408          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8409          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8410          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8411          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8412          *   <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
8413          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8414          * </ul>
8415          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8416          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8417          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8418          * that specified in order to enforce the viewport constraints.
8419          * Following are all of the supported anchor positions:
8420     <pre>
8421     Value  Description
8422     -----  -----------------------------
8423     tl     The top left corner (default)
8424     t      The center of the top edge
8425     tr     The top right corner
8426     l      The center of the left edge
8427     c      In the center of the element
8428     r      The center of the right edge
8429     bl     The bottom left corner
8430     b      The center of the bottom edge
8431     br     The bottom right corner
8432     </pre>
8433     Example Usage:
8434     <pre><code>
8435     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8436     el.alignTo("other-el");
8437
8438     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8439     el.alignTo("other-el", "tr?");
8440
8441     // align the bottom right corner of el with the center left edge of other-el
8442     el.alignTo("other-el", "br-l?");
8443
8444     // align the center of el with the bottom left corner of other-el and
8445     // adjust the x position by -6 pixels (and the y position by 0)
8446     el.alignTo("other-el", "c-bl", [-6, 0]);
8447     </code></pre>
8448          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8449          * @param {String} position The position to align to.
8450          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8451          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8452          * @return {Roo.Element} this
8453          */
8454         alignTo : function(element, position, offsets, animate){
8455             var xy = this.getAlignToXY(element, position, offsets);
8456             this.setXY(xy, this.preanim(arguments, 3));
8457             return this;
8458         },
8459
8460         /**
8461          * Anchors an element to another element and realigns it when the window is resized.
8462          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8463          * @param {String} position The position to align to.
8464          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8465          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8466          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8467          * is a number, it is used as the buffer delay (defaults to 50ms).
8468          * @param {Function} callback The function to call after the animation finishes
8469          * @return {Roo.Element} this
8470          */
8471         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8472             var action = function(){
8473                 this.alignTo(el, alignment, offsets, animate);
8474                 Roo.callback(callback, this);
8475             };
8476             Roo.EventManager.onWindowResize(action, this);
8477             var tm = typeof monitorScroll;
8478             if(tm != 'undefined'){
8479                 Roo.EventManager.on(window, 'scroll', action, this,
8480                     {buffer: tm == 'number' ? monitorScroll : 50});
8481             }
8482             action.call(this); // align immediately
8483             return this;
8484         },
8485         /**
8486          * Clears any opacity settings from this element. Required in some cases for IE.
8487          * @return {Roo.Element} this
8488          */
8489         clearOpacity : function(){
8490             if (window.ActiveXObject) {
8491                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8492                     this.dom.style.filter = "";
8493                 }
8494             } else {
8495                 this.dom.style.opacity = "";
8496                 this.dom.style["-moz-opacity"] = "";
8497                 this.dom.style["-khtml-opacity"] = "";
8498             }
8499             return this;
8500         },
8501
8502         /**
8503          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8504          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8505          * @return {Roo.Element} this
8506          */
8507         hide : function(animate){
8508             this.setVisible(false, this.preanim(arguments, 0));
8509             return this;
8510         },
8511
8512         /**
8513         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8514         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8515          * @return {Roo.Element} this
8516          */
8517         show : function(animate){
8518             this.setVisible(true, this.preanim(arguments, 0));
8519             return this;
8520         },
8521
8522         /**
8523          * @private Test if size has a unit, otherwise appends the default
8524          */
8525         addUnits : function(size){
8526             return Roo.Element.addUnits(size, this.defaultUnit);
8527         },
8528
8529         /**
8530          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8531          * @return {Roo.Element} this
8532          */
8533         beginMeasure : function(){
8534             var el = this.dom;
8535             if(el.offsetWidth || el.offsetHeight){
8536                 return this; // offsets work already
8537             }
8538             var changed = [];
8539             var p = this.dom, b = document.body; // start with this element
8540             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8541                 var pe = Roo.get(p);
8542                 if(pe.getStyle('display') == 'none'){
8543                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8544                     p.style.visibility = "hidden";
8545                     p.style.display = "block";
8546                 }
8547                 p = p.parentNode;
8548             }
8549             this._measureChanged = changed;
8550             return this;
8551
8552         },
8553
8554         /**
8555          * Restores displays to before beginMeasure was called
8556          * @return {Roo.Element} this
8557          */
8558         endMeasure : function(){
8559             var changed = this._measureChanged;
8560             if(changed){
8561                 for(var i = 0, len = changed.length; i < len; i++) {
8562                     var r = changed[i];
8563                     r.el.style.visibility = r.visibility;
8564                     r.el.style.display = "none";
8565                 }
8566                 this._measureChanged = null;
8567             }
8568             return this;
8569         },
8570
8571         /**
8572         * Update the innerHTML of this element, optionally searching for and processing scripts
8573         * @param {String} html The new HTML
8574         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8575         * @param {Function} callback For async script loading you can be noticed when the update completes
8576         * @return {Roo.Element} this
8577          */
8578         update : function(html, loadScripts, callback){
8579             if(typeof html == "undefined"){
8580                 html = "";
8581             }
8582             if(loadScripts !== true){
8583                 this.dom.innerHTML = html;
8584                 if(typeof callback == "function"){
8585                     callback();
8586                 }
8587                 return this;
8588             }
8589             var id = Roo.id();
8590             var dom = this.dom;
8591
8592             html += '<span id="' + id + '"></span>';
8593
8594             E.onAvailable(id, function(){
8595                 var hd = document.getElementsByTagName("head")[0];
8596                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8597                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8598                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8599
8600                 var match;
8601                 while(match = re.exec(html)){
8602                     var attrs = match[1];
8603                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8604                     if(srcMatch && srcMatch[2]){
8605                        var s = document.createElement("script");
8606                        s.src = srcMatch[2];
8607                        var typeMatch = attrs.match(typeRe);
8608                        if(typeMatch && typeMatch[2]){
8609                            s.type = typeMatch[2];
8610                        }
8611                        hd.appendChild(s);
8612                     }else if(match[2] && match[2].length > 0){
8613                         if(window.execScript) {
8614                            window.execScript(match[2]);
8615                         } else {
8616                             /**
8617                              * eval:var:id
8618                              * eval:var:dom
8619                              * eval:var:html
8620                              * 
8621                              */
8622                            window.eval(match[2]);
8623                         }
8624                     }
8625                 }
8626                 var el = document.getElementById(id);
8627                 if(el){el.parentNode.removeChild(el);}
8628                 if(typeof callback == "function"){
8629                     callback();
8630                 }
8631             });
8632             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8633             return this;
8634         },
8635
8636         /**
8637          * Direct access to the UpdateManager update() method (takes the same parameters).
8638          * @param {String/Function} url The url for this request or a function to call to get the url
8639          * @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}
8640          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8641          * @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.
8642          * @return {Roo.Element} this
8643          */
8644         load : function(){
8645             var um = this.getUpdateManager();
8646             um.update.apply(um, arguments);
8647             return this;
8648         },
8649
8650         /**
8651         * Gets this element's UpdateManager
8652         * @return {Roo.UpdateManager} The UpdateManager
8653         */
8654         getUpdateManager : function(){
8655             if(!this.updateManager){
8656                 this.updateManager = new Roo.UpdateManager(this);
8657             }
8658             return this.updateManager;
8659         },
8660
8661         /**
8662          * Disables text selection for this element (normalized across browsers)
8663          * @return {Roo.Element} this
8664          */
8665         unselectable : function(){
8666             this.dom.unselectable = "on";
8667             this.swallowEvent("selectstart", true);
8668             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8669             this.addClass("x-unselectable");
8670             return this;
8671         },
8672
8673         /**
8674         * Calculates the x, y to center this element on the screen
8675         * @return {Array} The x, y values [x, y]
8676         */
8677         getCenterXY : function(){
8678             return this.getAlignToXY(document, 'c-c');
8679         },
8680
8681         /**
8682         * Centers the Element in either the viewport, or another Element.
8683         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8684         */
8685         center : function(centerIn){
8686             this.alignTo(centerIn || document, 'c-c');
8687             return this;
8688         },
8689
8690         /**
8691          * Tests various css rules/browsers to determine if this element uses a border box
8692          * @return {Boolean}
8693          */
8694         isBorderBox : function(){
8695             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8696         },
8697
8698         /**
8699          * Return a box {x, y, width, height} that can be used to set another elements
8700          * size/location to match this element.
8701          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8702          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8703          * @return {Object} box An object in the format {x, y, width, height}
8704          */
8705         getBox : function(contentBox, local){
8706             var xy;
8707             if(!local){
8708                 xy = this.getXY();
8709             }else{
8710                 var left = parseInt(this.getStyle("left"), 10) || 0;
8711                 var top = parseInt(this.getStyle("top"), 10) || 0;
8712                 xy = [left, top];
8713             }
8714             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8715             if(!contentBox){
8716                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8717             }else{
8718                 var l = this.getBorderWidth("l")+this.getPadding("l");
8719                 var r = this.getBorderWidth("r")+this.getPadding("r");
8720                 var t = this.getBorderWidth("t")+this.getPadding("t");
8721                 var b = this.getBorderWidth("b")+this.getPadding("b");
8722                 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)};
8723             }
8724             bx.right = bx.x + bx.width;
8725             bx.bottom = bx.y + bx.height;
8726             return bx;
8727         },
8728
8729         /**
8730          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8731          for more information about the sides.
8732          * @param {String} sides
8733          * @return {Number}
8734          */
8735         getFrameWidth : function(sides, onlyContentBox){
8736             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8737         },
8738
8739         /**
8740          * 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.
8741          * @param {Object} box The box to fill {x, y, width, height}
8742          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8743          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8744          * @return {Roo.Element} this
8745          */
8746         setBox : function(box, adjust, animate){
8747             var w = box.width, h = box.height;
8748             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8749                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8750                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8751             }
8752             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8753             return this;
8754         },
8755
8756         /**
8757          * Forces the browser to repaint this element
8758          * @return {Roo.Element} this
8759          */
8760          repaint : function(){
8761             var dom = this.dom;
8762             this.addClass("x-repaint");
8763             setTimeout(function(){
8764                 Roo.get(dom).removeClass("x-repaint");
8765             }, 1);
8766             return this;
8767         },
8768
8769         /**
8770          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8771          * then it returns the calculated width of the sides (see getPadding)
8772          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8773          * @return {Object/Number}
8774          */
8775         getMargins : function(side){
8776             if(!side){
8777                 return {
8778                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8779                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8780                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8781                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8782                 };
8783             }else{
8784                 return this.addStyles(side, El.margins);
8785              }
8786         },
8787
8788         // private
8789         addStyles : function(sides, styles){
8790             var val = 0, v, w;
8791             for(var i = 0, len = sides.length; i < len; i++){
8792                 v = this.getStyle(styles[sides.charAt(i)]);
8793                 if(v){
8794                      w = parseInt(v, 10);
8795                      if(w){ val += w; }
8796                 }
8797             }
8798             return val;
8799         },
8800
8801         /**
8802          * Creates a proxy element of this element
8803          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8804          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8805          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8806          * @return {Roo.Element} The new proxy element
8807          */
8808         createProxy : function(config, renderTo, matchBox){
8809             if(renderTo){
8810                 renderTo = Roo.getDom(renderTo);
8811             }else{
8812                 renderTo = document.body;
8813             }
8814             config = typeof config == "object" ?
8815                 config : {tag : "div", cls: config};
8816             var proxy = Roo.DomHelper.append(renderTo, config, true);
8817             if(matchBox){
8818                proxy.setBox(this.getBox());
8819             }
8820             return proxy;
8821         },
8822
8823         /**
8824          * Puts a mask over this element to disable user interaction. Requires core.css.
8825          * This method can only be applied to elements which accept child nodes.
8826          * @param {String} msg (optional) A message to display in the mask
8827          * @param {String} msgCls (optional) A css class to apply to the msg element
8828          * @return {Element} The mask  element
8829          */
8830         mask : function(msg, msgCls){
8831             if(this.getStyle("position") == "static"){
8832                 this.setStyle("position", "relative");
8833             }
8834             if(!this._mask){
8835                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8836             }
8837             this.addClass("x-masked");
8838             this._mask.setDisplayed(true);
8839             if(typeof msg == 'string'){
8840                 if(!this._maskMsg){
8841                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8842                 }
8843                 var mm = this._maskMsg;
8844                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8845                 mm.dom.firstChild.innerHTML = msg;
8846                 mm.setDisplayed(true);
8847                 mm.center(this);
8848             }
8849             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8850                 this._mask.setHeight(this.getHeight());
8851             }
8852             return this._mask;
8853         },
8854
8855         /**
8856          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8857          * it is cached for reuse.
8858          */
8859         unmask : function(removeEl){
8860             if(this._mask){
8861                 if(removeEl === true){
8862                     this._mask.remove();
8863                     delete this._mask;
8864                     if(this._maskMsg){
8865                         this._maskMsg.remove();
8866                         delete this._maskMsg;
8867                     }
8868                 }else{
8869                     this._mask.setDisplayed(false);
8870                     if(this._maskMsg){
8871                         this._maskMsg.setDisplayed(false);
8872                     }
8873                 }
8874             }
8875             this.removeClass("x-masked");
8876         },
8877
8878         /**
8879          * Returns true if this element is masked
8880          * @return {Boolean}
8881          */
8882         isMasked : function(){
8883             return this._mask && this._mask.isVisible();
8884         },
8885
8886         /**
8887          * Creates an iframe shim for this element to keep selects and other windowed objects from
8888          * showing through.
8889          * @return {Roo.Element} The new shim element
8890          */
8891         createShim : function(){
8892             var el = document.createElement('iframe');
8893             el.frameBorder = 'no';
8894             el.className = 'roo-shim';
8895             if(Roo.isIE && Roo.isSecure){
8896                 el.src = Roo.SSL_SECURE_URL;
8897             }
8898             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8899             shim.autoBoxAdjust = false;
8900             return shim;
8901         },
8902
8903         /**
8904          * Removes this element from the DOM and deletes it from the cache
8905          */
8906         remove : function(){
8907             if(this.dom.parentNode){
8908                 this.dom.parentNode.removeChild(this.dom);
8909             }
8910             delete El.cache[this.dom.id];
8911         },
8912
8913         /**
8914          * Sets up event handlers to add and remove a css class when the mouse is over this element
8915          * @param {String} className
8916          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8917          * mouseout events for children elements
8918          * @return {Roo.Element} this
8919          */
8920         addClassOnOver : function(className, preventFlicker){
8921             this.on("mouseover", function(){
8922                 Roo.fly(this, '_internal').addClass(className);
8923             }, this.dom);
8924             var removeFn = function(e){
8925                 if(preventFlicker !== true || !e.within(this, true)){
8926                     Roo.fly(this, '_internal').removeClass(className);
8927                 }
8928             };
8929             this.on("mouseout", removeFn, this.dom);
8930             return this;
8931         },
8932
8933         /**
8934          * Sets up event handlers to add and remove a css class when this element has the focus
8935          * @param {String} className
8936          * @return {Roo.Element} this
8937          */
8938         addClassOnFocus : function(className){
8939             this.on("focus", function(){
8940                 Roo.fly(this, '_internal').addClass(className);
8941             }, this.dom);
8942             this.on("blur", function(){
8943                 Roo.fly(this, '_internal').removeClass(className);
8944             }, this.dom);
8945             return this;
8946         },
8947         /**
8948          * 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)
8949          * @param {String} className
8950          * @return {Roo.Element} this
8951          */
8952         addClassOnClick : function(className){
8953             var dom = this.dom;
8954             this.on("mousedown", function(){
8955                 Roo.fly(dom, '_internal').addClass(className);
8956                 var d = Roo.get(document);
8957                 var fn = function(){
8958                     Roo.fly(dom, '_internal').removeClass(className);
8959                     d.removeListener("mouseup", fn);
8960                 };
8961                 d.on("mouseup", fn);
8962             });
8963             return this;
8964         },
8965
8966         /**
8967          * Stops the specified event from bubbling and optionally prevents the default action
8968          * @param {String} eventName
8969          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8970          * @return {Roo.Element} this
8971          */
8972         swallowEvent : function(eventName, preventDefault){
8973             var fn = function(e){
8974                 e.stopPropagation();
8975                 if(preventDefault){
8976                     e.preventDefault();
8977                 }
8978             };
8979             if(eventName instanceof Array){
8980                 for(var i = 0, len = eventName.length; i < len; i++){
8981                      this.on(eventName[i], fn);
8982                 }
8983                 return this;
8984             }
8985             this.on(eventName, fn);
8986             return this;
8987         },
8988
8989         /**
8990          * @private
8991          */
8992       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8993
8994         /**
8995          * Sizes this element to its parent element's dimensions performing
8996          * neccessary box adjustments.
8997          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8998          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8999          * @return {Roo.Element} this
9000          */
9001         fitToParent : function(monitorResize, targetParent) {
9002           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9003           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9004           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9005             return;
9006           }
9007           var p = Roo.get(targetParent || this.dom.parentNode);
9008           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9009           if (monitorResize === true) {
9010             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9011             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9012           }
9013           return this;
9014         },
9015
9016         /**
9017          * Gets the next sibling, skipping text nodes
9018          * @return {HTMLElement} The next sibling or null
9019          */
9020         getNextSibling : function(){
9021             var n = this.dom.nextSibling;
9022             while(n && n.nodeType != 1){
9023                 n = n.nextSibling;
9024             }
9025             return n;
9026         },
9027
9028         /**
9029          * Gets the previous sibling, skipping text nodes
9030          * @return {HTMLElement} The previous sibling or null
9031          */
9032         getPrevSibling : function(){
9033             var n = this.dom.previousSibling;
9034             while(n && n.nodeType != 1){
9035                 n = n.previousSibling;
9036             }
9037             return n;
9038         },
9039
9040
9041         /**
9042          * Appends the passed element(s) to this element
9043          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9044          * @return {Roo.Element} this
9045          */
9046         appendChild: function(el){
9047             el = Roo.get(el);
9048             el.appendTo(this);
9049             return this;
9050         },
9051
9052         /**
9053          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9054          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9055          * automatically generated with the specified attributes.
9056          * @param {HTMLElement} insertBefore (optional) a child element of this element
9057          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9058          * @return {Roo.Element} The new child element
9059          */
9060         createChild: function(config, insertBefore, returnDom){
9061             config = config || {tag:'div'};
9062             if(insertBefore){
9063                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9064             }
9065             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9066         },
9067
9068         /**
9069          * Appends this element to the passed element
9070          * @param {String/HTMLElement/Element} el The new parent element
9071          * @return {Roo.Element} this
9072          */
9073         appendTo: function(el){
9074             el = Roo.getDom(el);
9075             el.appendChild(this.dom);
9076             return this;
9077         },
9078
9079         /**
9080          * Inserts this element before the passed element in the DOM
9081          * @param {String/HTMLElement/Element} el The element to insert before
9082          * @return {Roo.Element} this
9083          */
9084         insertBefore: function(el){
9085             el = Roo.getDom(el);
9086             el.parentNode.insertBefore(this.dom, el);
9087             return this;
9088         },
9089
9090         /**
9091          * Inserts this element after the passed element in the DOM
9092          * @param {String/HTMLElement/Element} el The element to insert after
9093          * @return {Roo.Element} this
9094          */
9095         insertAfter: function(el){
9096             el = Roo.getDom(el);
9097             el.parentNode.insertBefore(this.dom, el.nextSibling);
9098             return this;
9099         },
9100
9101         /**
9102          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9103          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9104          * @return {Roo.Element} The new child
9105          */
9106         insertFirst: function(el, returnDom){
9107             el = el || {};
9108             if(typeof el == 'object' && !el.nodeType){ // dh config
9109                 return this.createChild(el, this.dom.firstChild, returnDom);
9110             }else{
9111                 el = Roo.getDom(el);
9112                 this.dom.insertBefore(el, this.dom.firstChild);
9113                 return !returnDom ? Roo.get(el) : el;
9114             }
9115         },
9116
9117         /**
9118          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9119          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9120          * @param {String} where (optional) 'before' or 'after' defaults to before
9121          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9122          * @return {Roo.Element} the inserted Element
9123          */
9124         insertSibling: function(el, where, returnDom){
9125             where = where ? where.toLowerCase() : 'before';
9126             el = el || {};
9127             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9128
9129             if(typeof el == 'object' && !el.nodeType){ // dh config
9130                 if(where == 'after' && !this.dom.nextSibling){
9131                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9132                 }else{
9133                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9134                 }
9135
9136             }else{
9137                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9138                             where == 'before' ? this.dom : this.dom.nextSibling);
9139                 if(!returnDom){
9140                     rt = Roo.get(rt);
9141                 }
9142             }
9143             return rt;
9144         },
9145
9146         /**
9147          * Creates and wraps this element with another element
9148          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9149          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9150          * @return {HTMLElement/Element} The newly created wrapper element
9151          */
9152         wrap: function(config, returnDom){
9153             if(!config){
9154                 config = {tag: "div"};
9155             }
9156             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9157             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9158             return newEl;
9159         },
9160
9161         /**
9162          * Replaces the passed element with this element
9163          * @param {String/HTMLElement/Element} el The element to replace
9164          * @return {Roo.Element} this
9165          */
9166         replace: function(el){
9167             el = Roo.get(el);
9168             this.insertBefore(el);
9169             el.remove();
9170             return this;
9171         },
9172
9173         /**
9174          * Inserts an html fragment into this element
9175          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9176          * @param {String} html The HTML fragment
9177          * @param {Boolean} returnEl True to return an Roo.Element
9178          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9179          */
9180         insertHtml : function(where, html, returnEl){
9181             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9182             return returnEl ? Roo.get(el) : el;
9183         },
9184
9185         /**
9186          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9187          * @param {Object} o The object with the attributes
9188          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9189          * @return {Roo.Element} this
9190          */
9191         set : function(o, useSet){
9192             var el = this.dom;
9193             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9194             for(var attr in o){
9195                 if(attr == "style" || typeof o[attr] == "function") continue;
9196                 if(attr=="cls"){
9197                     el.className = o["cls"];
9198                 }else{
9199                     if(useSet) el.setAttribute(attr, o[attr]);
9200                     else el[attr] = o[attr];
9201                 }
9202             }
9203             if(o.style){
9204                 Roo.DomHelper.applyStyles(el, o.style);
9205             }
9206             return this;
9207         },
9208
9209         /**
9210          * Convenience method for constructing a KeyMap
9211          * @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:
9212          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9213          * @param {Function} fn The function to call
9214          * @param {Object} scope (optional) The scope of the function
9215          * @return {Roo.KeyMap} The KeyMap created
9216          */
9217         addKeyListener : function(key, fn, scope){
9218             var config;
9219             if(typeof key != "object" || key instanceof Array){
9220                 config = {
9221                     key: key,
9222                     fn: fn,
9223                     scope: scope
9224                 };
9225             }else{
9226                 config = {
9227                     key : key.key,
9228                     shift : key.shift,
9229                     ctrl : key.ctrl,
9230                     alt : key.alt,
9231                     fn: fn,
9232                     scope: scope
9233                 };
9234             }
9235             return new Roo.KeyMap(this, config);
9236         },
9237
9238         /**
9239          * Creates a KeyMap for this element
9240          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9241          * @return {Roo.KeyMap} The KeyMap created
9242          */
9243         addKeyMap : function(config){
9244             return new Roo.KeyMap(this, config);
9245         },
9246
9247         /**
9248          * Returns true if this element is scrollable.
9249          * @return {Boolean}
9250          */
9251          isScrollable : function(){
9252             var dom = this.dom;
9253             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9254         },
9255
9256         /**
9257          * 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().
9258          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9259          * @param {Number} value The new scroll value
9260          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9261          * @return {Element} this
9262          */
9263
9264         scrollTo : function(side, value, animate){
9265             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9266             if(!animate || !A){
9267                 this.dom[prop] = value;
9268             }else{
9269                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9270                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9271             }
9272             return this;
9273         },
9274
9275         /**
9276          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9277          * within this element's scrollable range.
9278          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9279          * @param {Number} distance How far to scroll the element in pixels
9280          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9281          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9282          * was scrolled as far as it could go.
9283          */
9284          scroll : function(direction, distance, animate){
9285              if(!this.isScrollable()){
9286                  return;
9287              }
9288              var el = this.dom;
9289              var l = el.scrollLeft, t = el.scrollTop;
9290              var w = el.scrollWidth, h = el.scrollHeight;
9291              var cw = el.clientWidth, ch = el.clientHeight;
9292              direction = direction.toLowerCase();
9293              var scrolled = false;
9294              var a = this.preanim(arguments, 2);
9295              switch(direction){
9296                  case "l":
9297                  case "left":
9298                      if(w - l > cw){
9299                          var v = Math.min(l + distance, w-cw);
9300                          this.scrollTo("left", v, a);
9301                          scrolled = true;
9302                      }
9303                      break;
9304                 case "r":
9305                 case "right":
9306                      if(l > 0){
9307                          var v = Math.max(l - distance, 0);
9308                          this.scrollTo("left", v, a);
9309                          scrolled = true;
9310                      }
9311                      break;
9312                 case "t":
9313                 case "top":
9314                 case "up":
9315                      if(t > 0){
9316                          var v = Math.max(t - distance, 0);
9317                          this.scrollTo("top", v, a);
9318                          scrolled = true;
9319                      }
9320                      break;
9321                 case "b":
9322                 case "bottom":
9323                 case "down":
9324                      if(h - t > ch){
9325                          var v = Math.min(t + distance, h-ch);
9326                          this.scrollTo("top", v, a);
9327                          scrolled = true;
9328                      }
9329                      break;
9330              }
9331              return scrolled;
9332         },
9333
9334         /**
9335          * Translates the passed page coordinates into left/top css values for this element
9336          * @param {Number/Array} x The page x or an array containing [x, y]
9337          * @param {Number} y The page y
9338          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9339          */
9340         translatePoints : function(x, y){
9341             if(typeof x == 'object' || x instanceof Array){
9342                 y = x[1]; x = x[0];
9343             }
9344             var p = this.getStyle('position');
9345             var o = this.getXY();
9346
9347             var l = parseInt(this.getStyle('left'), 10);
9348             var t = parseInt(this.getStyle('top'), 10);
9349
9350             if(isNaN(l)){
9351                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9352             }
9353             if(isNaN(t)){
9354                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9355             }
9356
9357             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9358         },
9359
9360         /**
9361          * Returns the current scroll position of the element.
9362          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9363          */
9364         getScroll : function(){
9365             var d = this.dom, doc = document;
9366             if(d == doc || d == doc.body){
9367                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9368                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9369                 return {left: l, top: t};
9370             }else{
9371                 return {left: d.scrollLeft, top: d.scrollTop};
9372             }
9373         },
9374
9375         /**
9376          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9377          * are convert to standard 6 digit hex color.
9378          * @param {String} attr The css attribute
9379          * @param {String} defaultValue The default value to use when a valid color isn't found
9380          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9381          * YUI color anims.
9382          */
9383         getColor : function(attr, defaultValue, prefix){
9384             var v = this.getStyle(attr);
9385             if(!v || v == "transparent" || v == "inherit") {
9386                 return defaultValue;
9387             }
9388             var color = typeof prefix == "undefined" ? "#" : prefix;
9389             if(v.substr(0, 4) == "rgb("){
9390                 var rvs = v.slice(4, v.length -1).split(",");
9391                 for(var i = 0; i < 3; i++){
9392                     var h = parseInt(rvs[i]).toString(16);
9393                     if(h < 16){
9394                         h = "0" + h;
9395                     }
9396                     color += h;
9397                 }
9398             } else {
9399                 if(v.substr(0, 1) == "#"){
9400                     if(v.length == 4) {
9401                         for(var i = 1; i < 4; i++){
9402                             var c = v.charAt(i);
9403                             color +=  c + c;
9404                         }
9405                     }else if(v.length == 7){
9406                         color += v.substr(1);
9407                     }
9408                 }
9409             }
9410             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9411         },
9412
9413         /**
9414          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9415          * gradient background, rounded corners and a 4-way shadow.
9416          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9417          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9418          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9419          * @return {Roo.Element} this
9420          */
9421         boxWrap : function(cls){
9422             cls = cls || 'x-box';
9423             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9424             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9425             return el;
9426         },
9427
9428         /**
9429          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9430          * @param {String} namespace The namespace in which to look for the attribute
9431          * @param {String} name The attribute name
9432          * @return {String} The attribute value
9433          */
9434         getAttributeNS : Roo.isIE ? function(ns, name){
9435             var d = this.dom;
9436             var type = typeof d[ns+":"+name];
9437             if(type != 'undefined' && type != 'unknown'){
9438                 return d[ns+":"+name];
9439             }
9440             return d[name];
9441         } : function(ns, name){
9442             var d = this.dom;
9443             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9444         }
9445     };
9446
9447     var ep = El.prototype;
9448
9449     /**
9450      * Appends an event handler (Shorthand for addListener)
9451      * @param {String}   eventName     The type of event to append
9452      * @param {Function} fn        The method the event invokes
9453      * @param {Object} scope       (optional) The scope (this object) of the fn
9454      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9455      * @method
9456      */
9457     ep.on = ep.addListener;
9458         // backwards compat
9459     ep.mon = ep.addListener;
9460
9461     /**
9462      * Removes an event handler from this element (shorthand for removeListener)
9463      * @param {String} eventName the type of event to remove
9464      * @param {Function} fn the method the event invokes
9465      * @return {Roo.Element} this
9466      * @method
9467      */
9468     ep.un = ep.removeListener;
9469
9470     /**
9471      * true to automatically adjust width and height settings for box-model issues (default to true)
9472      */
9473     ep.autoBoxAdjust = true;
9474
9475     // private
9476     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9477
9478     // private
9479     El.addUnits = function(v, defaultUnit){
9480         if(v === "" || v == "auto"){
9481             return v;
9482         }
9483         if(v === undefined){
9484             return '';
9485         }
9486         if(typeof v == "number" || !El.unitPattern.test(v)){
9487             return v + (defaultUnit || 'px');
9488         }
9489         return v;
9490     };
9491
9492     // special markup used throughout Roo when box wrapping elements
9493     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>';
9494     /**
9495      * Visibility mode constant - Use visibility to hide element
9496      * @static
9497      * @type Number
9498      */
9499     El.VISIBILITY = 1;
9500     /**
9501      * Visibility mode constant - Use display to hide element
9502      * @static
9503      * @type Number
9504      */
9505     El.DISPLAY = 2;
9506
9507     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9508     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9509     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9510
9511
9512
9513     /**
9514      * @private
9515      */
9516     El.cache = {};
9517
9518     var docEl;
9519
9520     /**
9521      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9522      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9523      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9524      * @return {Element} The Element object
9525      * @static
9526      */
9527     El.get = function(el){
9528         var ex, elm, id;
9529         if(!el){ return null; }
9530         if(typeof el == "string"){ // element id
9531             if(!(elm = document.getElementById(el))){
9532                 return null;
9533             }
9534             if(ex = El.cache[el]){
9535                 ex.dom = elm;
9536             }else{
9537                 ex = El.cache[el] = new El(elm);
9538             }
9539             return ex;
9540         }else if(el.tagName){ // dom element
9541             if(!(id = el.id)){
9542                 id = Roo.id(el);
9543             }
9544             if(ex = El.cache[id]){
9545                 ex.dom = el;
9546             }else{
9547                 ex = El.cache[id] = new El(el);
9548             }
9549             return ex;
9550         }else if(el instanceof El){
9551             if(el != docEl){
9552                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9553                                                               // catch case where it hasn't been appended
9554                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9555             }
9556             return el;
9557         }else if(el.isComposite){
9558             return el;
9559         }else if(el instanceof Array){
9560             return El.select(el);
9561         }else if(el == document){
9562             // create a bogus element object representing the document object
9563             if(!docEl){
9564                 var f = function(){};
9565                 f.prototype = El.prototype;
9566                 docEl = new f();
9567                 docEl.dom = document;
9568             }
9569             return docEl;
9570         }
9571         return null;
9572     };
9573
9574     // private
9575     El.uncache = function(el){
9576         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9577             if(a[i]){
9578                 delete El.cache[a[i].id || a[i]];
9579             }
9580         }
9581     };
9582
9583     // private
9584     // Garbage collection - uncache elements/purge listeners on orphaned elements
9585     // so we don't hold a reference and cause the browser to retain them
9586     El.garbageCollect = function(){
9587         if(!Roo.enableGarbageCollector){
9588             clearInterval(El.collectorThread);
9589             return;
9590         }
9591         for(var eid in El.cache){
9592             var el = El.cache[eid], d = el.dom;
9593             // -------------------------------------------------------
9594             // Determining what is garbage:
9595             // -------------------------------------------------------
9596             // !d
9597             // dom node is null, definitely garbage
9598             // -------------------------------------------------------
9599             // !d.parentNode
9600             // no parentNode == direct orphan, definitely garbage
9601             // -------------------------------------------------------
9602             // !d.offsetParent && !document.getElementById(eid)
9603             // display none elements have no offsetParent so we will
9604             // also try to look it up by it's id. However, check
9605             // offsetParent first so we don't do unneeded lookups.
9606             // This enables collection of elements that are not orphans
9607             // directly, but somewhere up the line they have an orphan
9608             // parent.
9609             // -------------------------------------------------------
9610             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9611                 delete El.cache[eid];
9612                 if(d && Roo.enableListenerCollection){
9613                     E.purgeElement(d);
9614                 }
9615             }
9616         }
9617     }
9618     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9619
9620
9621     // dom is optional
9622     El.Flyweight = function(dom){
9623         this.dom = dom;
9624     };
9625     El.Flyweight.prototype = El.prototype;
9626
9627     El._flyweights = {};
9628     /**
9629      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9630      * the dom node can be overwritten by other code.
9631      * @param {String/HTMLElement} el The dom node or id
9632      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9633      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9634      * @static
9635      * @return {Element} The shared Element object
9636      */
9637     El.fly = function(el, named){
9638         named = named || '_global';
9639         el = Roo.getDom(el);
9640         if(!el){
9641             return null;
9642         }
9643         if(!El._flyweights[named]){
9644             El._flyweights[named] = new El.Flyweight();
9645         }
9646         El._flyweights[named].dom = el;
9647         return El._flyweights[named];
9648     };
9649
9650     /**
9651      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9652      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9653      * Shorthand of {@link Roo.Element#get}
9654      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9655      * @return {Element} The Element object
9656      * @member Roo
9657      * @method get
9658      */
9659     Roo.get = El.get;
9660     /**
9661      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9662      * the dom node can be overwritten by other code.
9663      * Shorthand of {@link Roo.Element#fly}
9664      * @param {String/HTMLElement} el The dom node or id
9665      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9666      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9667      * @static
9668      * @return {Element} The shared Element object
9669      * @member Roo
9670      * @method fly
9671      */
9672     Roo.fly = El.fly;
9673
9674     // speedy lookup for elements never to box adjust
9675     var noBoxAdjust = Roo.isStrict ? {
9676         select:1
9677     } : {
9678         input:1, select:1, textarea:1
9679     };
9680     if(Roo.isIE || Roo.isGecko){
9681         noBoxAdjust['button'] = 1;
9682     }
9683
9684
9685     Roo.EventManager.on(window, 'unload', function(){
9686         delete El.cache;
9687         delete El._flyweights;
9688     });
9689 })();
9690
9691
9692
9693
9694 if(Roo.DomQuery){
9695     Roo.Element.selectorFunction = Roo.DomQuery.select;
9696 }
9697
9698 Roo.Element.select = function(selector, unique, root){
9699     var els;
9700     if(typeof selector == "string"){
9701         els = Roo.Element.selectorFunction(selector, root);
9702     }else if(selector.length !== undefined){
9703         els = selector;
9704     }else{
9705         throw "Invalid selector";
9706     }
9707     if(unique === true){
9708         return new Roo.CompositeElement(els);
9709     }else{
9710         return new Roo.CompositeElementLite(els);
9711     }
9712 };
9713 /**
9714  * Selects elements based on the passed CSS selector to enable working on them as 1.
9715  * @param {String/Array} selector The CSS selector or an array of elements
9716  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9717  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9718  * @return {CompositeElementLite/CompositeElement}
9719  * @member Roo
9720  * @method select
9721  */
9722 Roo.select = Roo.Element.select;
9723
9724
9725
9726
9727
9728
9729
9730
9731
9732
9733
9734
9735
9736
9737 /*
9738  * Based on:
9739  * Ext JS Library 1.1.1
9740  * Copyright(c) 2006-2007, Ext JS, LLC.
9741  *
9742  * Originally Released Under LGPL - original licence link has changed is not relivant.
9743  *
9744  * Fork - LGPL
9745  * <script type="text/javascript">
9746  */
9747
9748
9749
9750 //Notifies Element that fx methods are available
9751 Roo.enableFx = true;
9752
9753 /**
9754  * @class Roo.Fx
9755  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9756  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9757  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9758  * Element effects to work.</p><br/>
9759  *
9760  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9761  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9762  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9763  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9764  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9765  * expected results and should be done with care.</p><br/>
9766  *
9767  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9768  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9769 <pre>
9770 Value  Description
9771 -----  -----------------------------
9772 tl     The top left corner
9773 t      The center of the top edge
9774 tr     The top right corner
9775 l      The center of the left edge
9776 r      The center of the right edge
9777 bl     The bottom left corner
9778 b      The center of the bottom edge
9779 br     The bottom right corner
9780 </pre>
9781  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9782  * below are common options that can be passed to any Fx method.</b>
9783  * @cfg {Function} callback A function called when the effect is finished
9784  * @cfg {Object} scope The scope of the effect function
9785  * @cfg {String} easing A valid Easing value for the effect
9786  * @cfg {String} afterCls A css class to apply after the effect
9787  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9788  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9789  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9790  * effects that end with the element being visually hidden, ignored otherwise)
9791  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9792  * a function which returns such a specification that will be applied to the Element after the effect finishes
9793  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9794  * @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
9795  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9796  */
9797 Roo.Fx = {
9798         /**
9799          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9800          * origin for the slide effect.  This function automatically handles wrapping the element with
9801          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9802          * Usage:
9803          *<pre><code>
9804 // default: slide the element in from the top
9805 el.slideIn();
9806
9807 // custom: slide the element in from the right with a 2-second duration
9808 el.slideIn('r', { duration: 2 });
9809
9810 // common config options shown with default values
9811 el.slideIn('t', {
9812     easing: 'easeOut',
9813     duration: .5
9814 });
9815 </code></pre>
9816          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9817          * @param {Object} options (optional) Object literal with any of the Fx config options
9818          * @return {Roo.Element} The Element
9819          */
9820     slideIn : function(anchor, o){
9821         var el = this.getFxEl();
9822         o = o || {};
9823
9824         el.queueFx(o, function(){
9825
9826             anchor = anchor || "t";
9827
9828             // fix display to visibility
9829             this.fixDisplay();
9830
9831             // restore values after effect
9832             var r = this.getFxRestore();
9833             var b = this.getBox();
9834             // fixed size for slide
9835             this.setSize(b);
9836
9837             // wrap if needed
9838             var wrap = this.fxWrap(r.pos, o, "hidden");
9839
9840             var st = this.dom.style;
9841             st.visibility = "visible";
9842             st.position = "absolute";
9843
9844             // clear out temp styles after slide and unwrap
9845             var after = function(){
9846                 el.fxUnwrap(wrap, r.pos, o);
9847                 st.width = r.width;
9848                 st.height = r.height;
9849                 el.afterFx(o);
9850             };
9851             // time to calc the positions
9852             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9853
9854             switch(anchor.toLowerCase()){
9855                 case "t":
9856                     wrap.setSize(b.width, 0);
9857                     st.left = st.bottom = "0";
9858                     a = {height: bh};
9859                 break;
9860                 case "l":
9861                     wrap.setSize(0, b.height);
9862                     st.right = st.top = "0";
9863                     a = {width: bw};
9864                 break;
9865                 case "r":
9866                     wrap.setSize(0, b.height);
9867                     wrap.setX(b.right);
9868                     st.left = st.top = "0";
9869                     a = {width: bw, points: pt};
9870                 break;
9871                 case "b":
9872                     wrap.setSize(b.width, 0);
9873                     wrap.setY(b.bottom);
9874                     st.left = st.top = "0";
9875                     a = {height: bh, points: pt};
9876                 break;
9877                 case "tl":
9878                     wrap.setSize(0, 0);
9879                     st.right = st.bottom = "0";
9880                     a = {width: bw, height: bh};
9881                 break;
9882                 case "bl":
9883                     wrap.setSize(0, 0);
9884                     wrap.setY(b.y+b.height);
9885                     st.right = st.top = "0";
9886                     a = {width: bw, height: bh, points: pt};
9887                 break;
9888                 case "br":
9889                     wrap.setSize(0, 0);
9890                     wrap.setXY([b.right, b.bottom]);
9891                     st.left = st.top = "0";
9892                     a = {width: bw, height: bh, points: pt};
9893                 break;
9894                 case "tr":
9895                     wrap.setSize(0, 0);
9896                     wrap.setX(b.x+b.width);
9897                     st.left = st.bottom = "0";
9898                     a = {width: bw, height: bh, points: pt};
9899                 break;
9900             }
9901             this.dom.style.visibility = "visible";
9902             wrap.show();
9903
9904             arguments.callee.anim = wrap.fxanim(a,
9905                 o,
9906                 'motion',
9907                 .5,
9908                 'easeOut', after);
9909         });
9910         return this;
9911     },
9912     
9913         /**
9914          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9915          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9916          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9917          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9918          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9919          * Usage:
9920          *<pre><code>
9921 // default: slide the element out to the top
9922 el.slideOut();
9923
9924 // custom: slide the element out to the right with a 2-second duration
9925 el.slideOut('r', { duration: 2 });
9926
9927 // common config options shown with default values
9928 el.slideOut('t', {
9929     easing: 'easeOut',
9930     duration: .5,
9931     remove: false,
9932     useDisplay: false
9933 });
9934 </code></pre>
9935          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9936          * @param {Object} options (optional) Object literal with any of the Fx config options
9937          * @return {Roo.Element} The Element
9938          */
9939     slideOut : function(anchor, o){
9940         var el = this.getFxEl();
9941         o = o || {};
9942
9943         el.queueFx(o, function(){
9944
9945             anchor = anchor || "t";
9946
9947             // restore values after effect
9948             var r = this.getFxRestore();
9949             
9950             var b = this.getBox();
9951             // fixed size for slide
9952             this.setSize(b);
9953
9954             // wrap if needed
9955             var wrap = this.fxWrap(r.pos, o, "visible");
9956
9957             var st = this.dom.style;
9958             st.visibility = "visible";
9959             st.position = "absolute";
9960
9961             wrap.setSize(b);
9962
9963             var after = function(){
9964                 if(o.useDisplay){
9965                     el.setDisplayed(false);
9966                 }else{
9967                     el.hide();
9968                 }
9969
9970                 el.fxUnwrap(wrap, r.pos, o);
9971
9972                 st.width = r.width;
9973                 st.height = r.height;
9974
9975                 el.afterFx(o);
9976             };
9977
9978             var a, zero = {to: 0};
9979             switch(anchor.toLowerCase()){
9980                 case "t":
9981                     st.left = st.bottom = "0";
9982                     a = {height: zero};
9983                 break;
9984                 case "l":
9985                     st.right = st.top = "0";
9986                     a = {width: zero};
9987                 break;
9988                 case "r":
9989                     st.left = st.top = "0";
9990                     a = {width: zero, points: {to:[b.right, b.y]}};
9991                 break;
9992                 case "b":
9993                     st.left = st.top = "0";
9994                     a = {height: zero, points: {to:[b.x, b.bottom]}};
9995                 break;
9996                 case "tl":
9997                     st.right = st.bottom = "0";
9998                     a = {width: zero, height: zero};
9999                 break;
10000                 case "bl":
10001                     st.right = st.top = "0";
10002                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10003                 break;
10004                 case "br":
10005                     st.left = st.top = "0";
10006                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10007                 break;
10008                 case "tr":
10009                     st.left = st.bottom = "0";
10010                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10011                 break;
10012             }
10013
10014             arguments.callee.anim = wrap.fxanim(a,
10015                 o,
10016                 'motion',
10017                 .5,
10018                 "easeOut", after);
10019         });
10020         return this;
10021     },
10022
10023         /**
10024          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10025          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10026          * The element must be removed from the DOM using the 'remove' config option if desired.
10027          * Usage:
10028          *<pre><code>
10029 // default
10030 el.puff();
10031
10032 // common config options shown with default values
10033 el.puff({
10034     easing: 'easeOut',
10035     duration: .5,
10036     remove: false,
10037     useDisplay: false
10038 });
10039 </code></pre>
10040          * @param {Object} options (optional) Object literal with any of the Fx config options
10041          * @return {Roo.Element} The Element
10042          */
10043     puff : function(o){
10044         var el = this.getFxEl();
10045         o = o || {};
10046
10047         el.queueFx(o, function(){
10048             this.clearOpacity();
10049             this.show();
10050
10051             // restore values after effect
10052             var r = this.getFxRestore();
10053             var st = this.dom.style;
10054
10055             var after = function(){
10056                 if(o.useDisplay){
10057                     el.setDisplayed(false);
10058                 }else{
10059                     el.hide();
10060                 }
10061
10062                 el.clearOpacity();
10063
10064                 el.setPositioning(r.pos);
10065                 st.width = r.width;
10066                 st.height = r.height;
10067                 st.fontSize = '';
10068                 el.afterFx(o);
10069             };
10070
10071             var width = this.getWidth();
10072             var height = this.getHeight();
10073
10074             arguments.callee.anim = this.fxanim({
10075                     width : {to: this.adjustWidth(width * 2)},
10076                     height : {to: this.adjustHeight(height * 2)},
10077                     points : {by: [-(width * .5), -(height * .5)]},
10078                     opacity : {to: 0},
10079                     fontSize: {to:200, unit: "%"}
10080                 },
10081                 o,
10082                 'motion',
10083                 .5,
10084                 "easeOut", after);
10085         });
10086         return this;
10087     },
10088
10089         /**
10090          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10091          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10092          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10093          * Usage:
10094          *<pre><code>
10095 // default
10096 el.switchOff();
10097
10098 // all config options shown with default values
10099 el.switchOff({
10100     easing: 'easeIn',
10101     duration: .3,
10102     remove: false,
10103     useDisplay: false
10104 });
10105 </code></pre>
10106          * @param {Object} options (optional) Object literal with any of the Fx config options
10107          * @return {Roo.Element} The Element
10108          */
10109     switchOff : function(o){
10110         var el = this.getFxEl();
10111         o = o || {};
10112
10113         el.queueFx(o, function(){
10114             this.clearOpacity();
10115             this.clip();
10116
10117             // restore values after effect
10118             var r = this.getFxRestore();
10119             var st = this.dom.style;
10120
10121             var after = function(){
10122                 if(o.useDisplay){
10123                     el.setDisplayed(false);
10124                 }else{
10125                     el.hide();
10126                 }
10127
10128                 el.clearOpacity();
10129                 el.setPositioning(r.pos);
10130                 st.width = r.width;
10131                 st.height = r.height;
10132
10133                 el.afterFx(o);
10134             };
10135
10136             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10137                 this.clearOpacity();
10138                 (function(){
10139                     this.fxanim({
10140                         height:{to:1},
10141                         points:{by:[0, this.getHeight() * .5]}
10142                     }, o, 'motion', 0.3, 'easeIn', after);
10143                 }).defer(100, this);
10144             });
10145         });
10146         return this;
10147     },
10148
10149     /**
10150      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10151      * changed using the "attr" config option) and then fading back to the original color. If no original
10152      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10153      * Usage:
10154 <pre><code>
10155 // default: highlight background to yellow
10156 el.highlight();
10157
10158 // custom: highlight foreground text to blue for 2 seconds
10159 el.highlight("0000ff", { attr: 'color', duration: 2 });
10160
10161 // common config options shown with default values
10162 el.highlight("ffff9c", {
10163     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10164     endColor: (current color) or "ffffff",
10165     easing: 'easeIn',
10166     duration: 1
10167 });
10168 </code></pre>
10169      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10170      * @param {Object} options (optional) Object literal with any of the Fx config options
10171      * @return {Roo.Element} The Element
10172      */ 
10173     highlight : function(color, o){
10174         var el = this.getFxEl();
10175         o = o || {};
10176
10177         el.queueFx(o, function(){
10178             color = color || "ffff9c";
10179             attr = o.attr || "backgroundColor";
10180
10181             this.clearOpacity();
10182             this.show();
10183
10184             var origColor = this.getColor(attr);
10185             var restoreColor = this.dom.style[attr];
10186             endColor = (o.endColor || origColor) || "ffffff";
10187
10188             var after = function(){
10189                 el.dom.style[attr] = restoreColor;
10190                 el.afterFx(o);
10191             };
10192
10193             var a = {};
10194             a[attr] = {from: color, to: endColor};
10195             arguments.callee.anim = this.fxanim(a,
10196                 o,
10197                 'color',
10198                 1,
10199                 'easeIn', after);
10200         });
10201         return this;
10202     },
10203
10204    /**
10205     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10206     * Usage:
10207 <pre><code>
10208 // default: a single light blue ripple
10209 el.frame();
10210
10211 // custom: 3 red ripples lasting 3 seconds total
10212 el.frame("ff0000", 3, { duration: 3 });
10213
10214 // common config options shown with default values
10215 el.frame("C3DAF9", 1, {
10216     duration: 1 //duration of entire animation (not each individual ripple)
10217     // Note: Easing is not configurable and will be ignored if included
10218 });
10219 </code></pre>
10220     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10221     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10222     * @param {Object} options (optional) Object literal with any of the Fx config options
10223     * @return {Roo.Element} The Element
10224     */
10225     frame : function(color, count, o){
10226         var el = this.getFxEl();
10227         o = o || {};
10228
10229         el.queueFx(o, function(){
10230             color = color || "#C3DAF9";
10231             if(color.length == 6){
10232                 color = "#" + color;
10233             }
10234             count = count || 1;
10235             duration = o.duration || 1;
10236             this.show();
10237
10238             var b = this.getBox();
10239             var animFn = function(){
10240                 var proxy = this.createProxy({
10241
10242                      style:{
10243                         visbility:"hidden",
10244                         position:"absolute",
10245                         "z-index":"35000", // yee haw
10246                         border:"0px solid " + color
10247                      }
10248                   });
10249                 var scale = Roo.isBorderBox ? 2 : 1;
10250                 proxy.animate({
10251                     top:{from:b.y, to:b.y - 20},
10252                     left:{from:b.x, to:b.x - 20},
10253                     borderWidth:{from:0, to:10},
10254                     opacity:{from:1, to:0},
10255                     height:{from:b.height, to:(b.height + (20*scale))},
10256                     width:{from:b.width, to:(b.width + (20*scale))}
10257                 }, duration, function(){
10258                     proxy.remove();
10259                 });
10260                 if(--count > 0){
10261                      animFn.defer((duration/2)*1000, this);
10262                 }else{
10263                     el.afterFx(o);
10264                 }
10265             };
10266             animFn.call(this);
10267         });
10268         return this;
10269     },
10270
10271    /**
10272     * Creates a pause before any subsequent queued effects begin.  If there are
10273     * no effects queued after the pause it will have no effect.
10274     * Usage:
10275 <pre><code>
10276 el.pause(1);
10277 </code></pre>
10278     * @param {Number} seconds The length of time to pause (in seconds)
10279     * @return {Roo.Element} The Element
10280     */
10281     pause : function(seconds){
10282         var el = this.getFxEl();
10283         var o = {};
10284
10285         el.queueFx(o, function(){
10286             setTimeout(function(){
10287                 el.afterFx(o);
10288             }, seconds * 1000);
10289         });
10290         return this;
10291     },
10292
10293    /**
10294     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10295     * using the "endOpacity" config option.
10296     * Usage:
10297 <pre><code>
10298 // default: fade in from opacity 0 to 100%
10299 el.fadeIn();
10300
10301 // custom: fade in from opacity 0 to 75% over 2 seconds
10302 el.fadeIn({ endOpacity: .75, duration: 2});
10303
10304 // common config options shown with default values
10305 el.fadeIn({
10306     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10307     easing: 'easeOut',
10308     duration: .5
10309 });
10310 </code></pre>
10311     * @param {Object} options (optional) Object literal with any of the Fx config options
10312     * @return {Roo.Element} The Element
10313     */
10314     fadeIn : function(o){
10315         var el = this.getFxEl();
10316         o = o || {};
10317         el.queueFx(o, function(){
10318             this.setOpacity(0);
10319             this.fixDisplay();
10320             this.dom.style.visibility = 'visible';
10321             var to = o.endOpacity || 1;
10322             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10323                 o, null, .5, "easeOut", function(){
10324                 if(to == 1){
10325                     this.clearOpacity();
10326                 }
10327                 el.afterFx(o);
10328             });
10329         });
10330         return this;
10331     },
10332
10333    /**
10334     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10335     * using the "endOpacity" config option.
10336     * Usage:
10337 <pre><code>
10338 // default: fade out from the element's current opacity to 0
10339 el.fadeOut();
10340
10341 // custom: fade out from the element's current opacity to 25% over 2 seconds
10342 el.fadeOut({ endOpacity: .25, duration: 2});
10343
10344 // common config options shown with default values
10345 el.fadeOut({
10346     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10347     easing: 'easeOut',
10348     duration: .5
10349     remove: false,
10350     useDisplay: false
10351 });
10352 </code></pre>
10353     * @param {Object} options (optional) Object literal with any of the Fx config options
10354     * @return {Roo.Element} The Element
10355     */
10356     fadeOut : function(o){
10357         var el = this.getFxEl();
10358         o = o || {};
10359         el.queueFx(o, function(){
10360             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10361                 o, null, .5, "easeOut", function(){
10362                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10363                      this.dom.style.display = "none";
10364                 }else{
10365                      this.dom.style.visibility = "hidden";
10366                 }
10367                 this.clearOpacity();
10368                 el.afterFx(o);
10369             });
10370         });
10371         return this;
10372     },
10373
10374    /**
10375     * Animates the transition of an element's dimensions from a starting height/width
10376     * to an ending height/width.
10377     * Usage:
10378 <pre><code>
10379 // change height and width to 100x100 pixels
10380 el.scale(100, 100);
10381
10382 // common config options shown with default values.  The height and width will default to
10383 // the element's existing values if passed as null.
10384 el.scale(
10385     [element's width],
10386     [element's height], {
10387     easing: 'easeOut',
10388     duration: .35
10389 });
10390 </code></pre>
10391     * @param {Number} width  The new width (pass undefined to keep the original width)
10392     * @param {Number} height  The new height (pass undefined to keep the original height)
10393     * @param {Object} options (optional) Object literal with any of the Fx config options
10394     * @return {Roo.Element} The Element
10395     */
10396     scale : function(w, h, o){
10397         this.shift(Roo.apply({}, o, {
10398             width: w,
10399             height: h
10400         }));
10401         return this;
10402     },
10403
10404    /**
10405     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10406     * Any of these properties not specified in the config object will not be changed.  This effect 
10407     * requires that at least one new dimension, position or opacity setting must be passed in on
10408     * the config object in order for the function to have any effect.
10409     * Usage:
10410 <pre><code>
10411 // slide the element horizontally to x position 200 while changing the height and opacity
10412 el.shift({ x: 200, height: 50, opacity: .8 });
10413
10414 // common config options shown with default values.
10415 el.shift({
10416     width: [element's width],
10417     height: [element's height],
10418     x: [element's x position],
10419     y: [element's y position],
10420     opacity: [element's opacity],
10421     easing: 'easeOut',
10422     duration: .35
10423 });
10424 </code></pre>
10425     * @param {Object} options  Object literal with any of the Fx config options
10426     * @return {Roo.Element} The Element
10427     */
10428     shift : function(o){
10429         var el = this.getFxEl();
10430         o = o || {};
10431         el.queueFx(o, function(){
10432             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10433             if(w !== undefined){
10434                 a.width = {to: this.adjustWidth(w)};
10435             }
10436             if(h !== undefined){
10437                 a.height = {to: this.adjustHeight(h)};
10438             }
10439             if(x !== undefined || y !== undefined){
10440                 a.points = {to: [
10441                     x !== undefined ? x : this.getX(),
10442                     y !== undefined ? y : this.getY()
10443                 ]};
10444             }
10445             if(op !== undefined){
10446                 a.opacity = {to: op};
10447             }
10448             if(o.xy !== undefined){
10449                 a.points = {to: o.xy};
10450             }
10451             arguments.callee.anim = this.fxanim(a,
10452                 o, 'motion', .35, "easeOut", function(){
10453                 el.afterFx(o);
10454             });
10455         });
10456         return this;
10457     },
10458
10459         /**
10460          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10461          * ending point of the effect.
10462          * Usage:
10463          *<pre><code>
10464 // default: slide the element downward while fading out
10465 el.ghost();
10466
10467 // custom: slide the element out to the right with a 2-second duration
10468 el.ghost('r', { duration: 2 });
10469
10470 // common config options shown with default values
10471 el.ghost('b', {
10472     easing: 'easeOut',
10473     duration: .5
10474     remove: false,
10475     useDisplay: false
10476 });
10477 </code></pre>
10478          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10479          * @param {Object} options (optional) Object literal with any of the Fx config options
10480          * @return {Roo.Element} The Element
10481          */
10482     ghost : function(anchor, o){
10483         var el = this.getFxEl();
10484         o = o || {};
10485
10486         el.queueFx(o, function(){
10487             anchor = anchor || "b";
10488
10489             // restore values after effect
10490             var r = this.getFxRestore();
10491             var w = this.getWidth(),
10492                 h = this.getHeight();
10493
10494             var st = this.dom.style;
10495
10496             var after = function(){
10497                 if(o.useDisplay){
10498                     el.setDisplayed(false);
10499                 }else{
10500                     el.hide();
10501                 }
10502
10503                 el.clearOpacity();
10504                 el.setPositioning(r.pos);
10505                 st.width = r.width;
10506                 st.height = r.height;
10507
10508                 el.afterFx(o);
10509             };
10510
10511             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10512             switch(anchor.toLowerCase()){
10513                 case "t":
10514                     pt.by = [0, -h];
10515                 break;
10516                 case "l":
10517                     pt.by = [-w, 0];
10518                 break;
10519                 case "r":
10520                     pt.by = [w, 0];
10521                 break;
10522                 case "b":
10523                     pt.by = [0, h];
10524                 break;
10525                 case "tl":
10526                     pt.by = [-w, -h];
10527                 break;
10528                 case "bl":
10529                     pt.by = [-w, h];
10530                 break;
10531                 case "br":
10532                     pt.by = [w, h];
10533                 break;
10534                 case "tr":
10535                     pt.by = [w, -h];
10536                 break;
10537             }
10538
10539             arguments.callee.anim = this.fxanim(a,
10540                 o,
10541                 'motion',
10542                 .5,
10543                 "easeOut", after);
10544         });
10545         return this;
10546     },
10547
10548         /**
10549          * Ensures that all effects queued after syncFx is called on the element are
10550          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10551          * @return {Roo.Element} The Element
10552          */
10553     syncFx : function(){
10554         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10555             block : false,
10556             concurrent : true,
10557             stopFx : false
10558         });
10559         return this;
10560     },
10561
10562         /**
10563          * Ensures that all effects queued after sequenceFx is called on the element are
10564          * run in sequence.  This is the opposite of {@link #syncFx}.
10565          * @return {Roo.Element} The Element
10566          */
10567     sequenceFx : function(){
10568         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10569             block : false,
10570             concurrent : false,
10571             stopFx : false
10572         });
10573         return this;
10574     },
10575
10576         /* @private */
10577     nextFx : function(){
10578         var ef = this.fxQueue[0];
10579         if(ef){
10580             ef.call(this);
10581         }
10582     },
10583
10584         /**
10585          * Returns true if the element has any effects actively running or queued, else returns false.
10586          * @return {Boolean} True if element has active effects, else false
10587          */
10588     hasActiveFx : function(){
10589         return this.fxQueue && this.fxQueue[0];
10590     },
10591
10592         /**
10593          * Stops any running effects and clears the element's internal effects queue if it contains
10594          * any additional effects that haven't started yet.
10595          * @return {Roo.Element} The Element
10596          */
10597     stopFx : function(){
10598         if(this.hasActiveFx()){
10599             var cur = this.fxQueue[0];
10600             if(cur && cur.anim && cur.anim.isAnimated()){
10601                 this.fxQueue = [cur]; // clear out others
10602                 cur.anim.stop(true);
10603             }
10604         }
10605         return this;
10606     },
10607
10608         /* @private */
10609     beforeFx : function(o){
10610         if(this.hasActiveFx() && !o.concurrent){
10611            if(o.stopFx){
10612                this.stopFx();
10613                return true;
10614            }
10615            return false;
10616         }
10617         return true;
10618     },
10619
10620         /**
10621          * Returns true if the element is currently blocking so that no other effect can be queued
10622          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10623          * used to ensure that an effect initiated by a user action runs to completion prior to the
10624          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10625          * @return {Boolean} True if blocking, else false
10626          */
10627     hasFxBlock : function(){
10628         var q = this.fxQueue;
10629         return q && q[0] && q[0].block;
10630     },
10631
10632         /* @private */
10633     queueFx : function(o, fn){
10634         if(!this.fxQueue){
10635             this.fxQueue = [];
10636         }
10637         if(!this.hasFxBlock()){
10638             Roo.applyIf(o, this.fxDefaults);
10639             if(!o.concurrent){
10640                 var run = this.beforeFx(o);
10641                 fn.block = o.block;
10642                 this.fxQueue.push(fn);
10643                 if(run){
10644                     this.nextFx();
10645                 }
10646             }else{
10647                 fn.call(this);
10648             }
10649         }
10650         return this;
10651     },
10652
10653         /* @private */
10654     fxWrap : function(pos, o, vis){
10655         var wrap;
10656         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10657             var wrapXY;
10658             if(o.fixPosition){
10659                 wrapXY = this.getXY();
10660             }
10661             var div = document.createElement("div");
10662             div.style.visibility = vis;
10663             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10664             wrap.setPositioning(pos);
10665             if(wrap.getStyle("position") == "static"){
10666                 wrap.position("relative");
10667             }
10668             this.clearPositioning('auto');
10669             wrap.clip();
10670             wrap.dom.appendChild(this.dom);
10671             if(wrapXY){
10672                 wrap.setXY(wrapXY);
10673             }
10674         }
10675         return wrap;
10676     },
10677
10678         /* @private */
10679     fxUnwrap : function(wrap, pos, o){
10680         this.clearPositioning();
10681         this.setPositioning(pos);
10682         if(!o.wrap){
10683             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10684             wrap.remove();
10685         }
10686     },
10687
10688         /* @private */
10689     getFxRestore : function(){
10690         var st = this.dom.style;
10691         return {pos: this.getPositioning(), width: st.width, height : st.height};
10692     },
10693
10694         /* @private */
10695     afterFx : function(o){
10696         if(o.afterStyle){
10697             this.applyStyles(o.afterStyle);
10698         }
10699         if(o.afterCls){
10700             this.addClass(o.afterCls);
10701         }
10702         if(o.remove === true){
10703             this.remove();
10704         }
10705         Roo.callback(o.callback, o.scope, [this]);
10706         if(!o.concurrent){
10707             this.fxQueue.shift();
10708             this.nextFx();
10709         }
10710     },
10711
10712         /* @private */
10713     getFxEl : function(){ // support for composite element fx
10714         return Roo.get(this.dom);
10715     },
10716
10717         /* @private */
10718     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10719         animType = animType || 'run';
10720         opt = opt || {};
10721         var anim = Roo.lib.Anim[animType](
10722             this.dom, args,
10723             (opt.duration || defaultDur) || .35,
10724             (opt.easing || defaultEase) || 'easeOut',
10725             function(){
10726                 Roo.callback(cb, this);
10727             },
10728             this
10729         );
10730         opt.anim = anim;
10731         return anim;
10732     }
10733 };
10734
10735 // backwords compat
10736 Roo.Fx.resize = Roo.Fx.scale;
10737
10738 //When included, Roo.Fx is automatically applied to Element so that all basic
10739 //effects are available directly via the Element API
10740 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10741  * Based on:
10742  * Ext JS Library 1.1.1
10743  * Copyright(c) 2006-2007, Ext JS, LLC.
10744  *
10745  * Originally Released Under LGPL - original licence link has changed is not relivant.
10746  *
10747  * Fork - LGPL
10748  * <script type="text/javascript">
10749  */
10750
10751
10752 /**
10753  * @class Roo.CompositeElement
10754  * Standard composite class. Creates a Roo.Element for every element in the collection.
10755  * <br><br>
10756  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10757  * actions will be performed on all the elements in this collection.</b>
10758  * <br><br>
10759  * All methods return <i>this</i> and can be chained.
10760  <pre><code>
10761  var els = Roo.select("#some-el div.some-class", true);
10762  // or select directly from an existing element
10763  var el = Roo.get('some-el');
10764  el.select('div.some-class', true);
10765
10766  els.setWidth(100); // all elements become 100 width
10767  els.hide(true); // all elements fade out and hide
10768  // or
10769  els.setWidth(100).hide(true);
10770  </code></pre>
10771  */
10772 Roo.CompositeElement = function(els){
10773     this.elements = [];
10774     this.addElements(els);
10775 };
10776 Roo.CompositeElement.prototype = {
10777     isComposite: true,
10778     addElements : function(els){
10779         if(!els) return this;
10780         if(typeof els == "string"){
10781             els = Roo.Element.selectorFunction(els);
10782         }
10783         var yels = this.elements;
10784         var index = yels.length-1;
10785         for(var i = 0, len = els.length; i < len; i++) {
10786                 yels[++index] = Roo.get(els[i]);
10787         }
10788         return this;
10789     },
10790
10791     /**
10792     * Clears this composite and adds the elements returned by the passed selector.
10793     * @param {String/Array} els A string CSS selector, an array of elements or an element
10794     * @return {CompositeElement} this
10795     */
10796     fill : function(els){
10797         this.elements = [];
10798         this.add(els);
10799         return this;
10800     },
10801
10802     /**
10803     * Filters this composite to only elements that match the passed selector.
10804     * @param {String} selector A string CSS selector
10805     * @return {CompositeElement} this
10806     */
10807     filter : function(selector){
10808         var els = [];
10809         this.each(function(el){
10810             if(el.is(selector)){
10811                 els[els.length] = el.dom;
10812             }
10813         });
10814         this.fill(els);
10815         return this;
10816     },
10817
10818     invoke : function(fn, args){
10819         var els = this.elements;
10820         for(var i = 0, len = els.length; i < len; i++) {
10821                 Roo.Element.prototype[fn].apply(els[i], args);
10822         }
10823         return this;
10824     },
10825     /**
10826     * Adds elements to this composite.
10827     * @param {String/Array} els A string CSS selector, an array of elements or an element
10828     * @return {CompositeElement} this
10829     */
10830     add : function(els){
10831         if(typeof els == "string"){
10832             this.addElements(Roo.Element.selectorFunction(els));
10833         }else if(els.length !== undefined){
10834             this.addElements(els);
10835         }else{
10836             this.addElements([els]);
10837         }
10838         return this;
10839     },
10840     /**
10841     * Calls the passed function passing (el, this, index) for each element in this composite.
10842     * @param {Function} fn The function to call
10843     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10844     * @return {CompositeElement} this
10845     */
10846     each : function(fn, scope){
10847         var els = this.elements;
10848         for(var i = 0, len = els.length; i < len; i++){
10849             if(fn.call(scope || els[i], els[i], this, i) === false) {
10850                 break;
10851             }
10852         }
10853         return this;
10854     },
10855
10856     /**
10857      * Returns the Element object at the specified index
10858      * @param {Number} index
10859      * @return {Roo.Element}
10860      */
10861     item : function(index){
10862         return this.elements[index] || null;
10863     },
10864
10865     /**
10866      * Returns the first Element
10867      * @return {Roo.Element}
10868      */
10869     first : function(){
10870         return this.item(0);
10871     },
10872
10873     /**
10874      * Returns the last Element
10875      * @return {Roo.Element}
10876      */
10877     last : function(){
10878         return this.item(this.elements.length-1);
10879     },
10880
10881     /**
10882      * Returns the number of elements in this composite
10883      * @return Number
10884      */
10885     getCount : function(){
10886         return this.elements.length;
10887     },
10888
10889     /**
10890      * Returns true if this composite contains the passed element
10891      * @return Boolean
10892      */
10893     contains : function(el){
10894         return this.indexOf(el) !== -1;
10895     },
10896
10897     /**
10898      * Returns true if this composite contains the passed element
10899      * @return Boolean
10900      */
10901     indexOf : function(el){
10902         return this.elements.indexOf(Roo.get(el));
10903     },
10904
10905
10906     /**
10907     * Removes the specified element(s).
10908     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10909     * or an array of any of those.
10910     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10911     * @return {CompositeElement} this
10912     */
10913     removeElement : function(el, removeDom){
10914         if(el instanceof Array){
10915             for(var i = 0, len = el.length; i < len; i++){
10916                 this.removeElement(el[i]);
10917             }
10918             return this;
10919         }
10920         var index = typeof el == 'number' ? el : this.indexOf(el);
10921         if(index !== -1){
10922             if(removeDom){
10923                 var d = this.elements[index];
10924                 if(d.dom){
10925                     d.remove();
10926                 }else{
10927                     d.parentNode.removeChild(d);
10928                 }
10929             }
10930             this.elements.splice(index, 1);
10931         }
10932         return this;
10933     },
10934
10935     /**
10936     * Replaces the specified element with the passed element.
10937     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10938     * to replace.
10939     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10940     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10941     * @return {CompositeElement} this
10942     */
10943     replaceElement : function(el, replacement, domReplace){
10944         var index = typeof el == 'number' ? el : this.indexOf(el);
10945         if(index !== -1){
10946             if(domReplace){
10947                 this.elements[index].replaceWith(replacement);
10948             }else{
10949                 this.elements.splice(index, 1, Roo.get(replacement))
10950             }
10951         }
10952         return this;
10953     },
10954
10955     /**
10956      * Removes all elements.
10957      */
10958     clear : function(){
10959         this.elements = [];
10960     }
10961 };
10962 (function(){
10963     Roo.CompositeElement.createCall = function(proto, fnName){
10964         if(!proto[fnName]){
10965             proto[fnName] = function(){
10966                 return this.invoke(fnName, arguments);
10967             };
10968         }
10969     };
10970     for(var fnName in Roo.Element.prototype){
10971         if(typeof Roo.Element.prototype[fnName] == "function"){
10972             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10973         }
10974     };
10975 })();
10976 /*
10977  * Based on:
10978  * Ext JS Library 1.1.1
10979  * Copyright(c) 2006-2007, Ext JS, LLC.
10980  *
10981  * Originally Released Under LGPL - original licence link has changed is not relivant.
10982  *
10983  * Fork - LGPL
10984  * <script type="text/javascript">
10985  */
10986
10987 /**
10988  * @class Roo.CompositeElementLite
10989  * @extends Roo.CompositeElement
10990  * Flyweight composite class. Reuses the same Roo.Element for element operations.
10991  <pre><code>
10992  var els = Roo.select("#some-el div.some-class");
10993  // or select directly from an existing element
10994  var el = Roo.get('some-el');
10995  el.select('div.some-class');
10996
10997  els.setWidth(100); // all elements become 100 width
10998  els.hide(true); // all elements fade out and hide
10999  // or
11000  els.setWidth(100).hide(true);
11001  </code></pre><br><br>
11002  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11003  * actions will be performed on all the elements in this collection.</b>
11004  */
11005 Roo.CompositeElementLite = function(els){
11006     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11007     this.el = new Roo.Element.Flyweight();
11008 };
11009 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11010     addElements : function(els){
11011         if(els){
11012             if(els instanceof Array){
11013                 this.elements = this.elements.concat(els);
11014             }else{
11015                 var yels = this.elements;
11016                 var index = yels.length-1;
11017                 for(var i = 0, len = els.length; i < len; i++) {
11018                     yels[++index] = els[i];
11019                 }
11020             }
11021         }
11022         return this;
11023     },
11024     invoke : function(fn, args){
11025         var els = this.elements;
11026         var el = this.el;
11027         for(var i = 0, len = els.length; i < len; i++) {
11028             el.dom = els[i];
11029                 Roo.Element.prototype[fn].apply(el, args);
11030         }
11031         return this;
11032     },
11033     /**
11034      * Returns a flyweight Element of the dom element object at the specified index
11035      * @param {Number} index
11036      * @return {Roo.Element}
11037      */
11038     item : function(index){
11039         if(!this.elements[index]){
11040             return null;
11041         }
11042         this.el.dom = this.elements[index];
11043         return this.el;
11044     },
11045
11046     // fixes scope with flyweight
11047     addListener : function(eventName, handler, scope, opt){
11048         var els = this.elements;
11049         for(var i = 0, len = els.length; i < len; i++) {
11050             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11051         }
11052         return this;
11053     },
11054
11055     /**
11056     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11057     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11058     * a reference to the dom node, use el.dom.</b>
11059     * @param {Function} fn The function to call
11060     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11061     * @return {CompositeElement} this
11062     */
11063     each : function(fn, scope){
11064         var els = this.elements;
11065         var el = this.el;
11066         for(var i = 0, len = els.length; i < len; i++){
11067             el.dom = els[i];
11068                 if(fn.call(scope || el, el, this, i) === false){
11069                 break;
11070             }
11071         }
11072         return this;
11073     },
11074
11075     indexOf : function(el){
11076         return this.elements.indexOf(Roo.getDom(el));
11077     },
11078
11079     replaceElement : function(el, replacement, domReplace){
11080         var index = typeof el == 'number' ? el : this.indexOf(el);
11081         if(index !== -1){
11082             replacement = Roo.getDom(replacement);
11083             if(domReplace){
11084                 var d = this.elements[index];
11085                 d.parentNode.insertBefore(replacement, d);
11086                 d.parentNode.removeChild(d);
11087             }
11088             this.elements.splice(index, 1, replacement);
11089         }
11090         return this;
11091     }
11092 });
11093 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11094
11095 /*
11096  * Based on:
11097  * Ext JS Library 1.1.1
11098  * Copyright(c) 2006-2007, Ext JS, LLC.
11099  *
11100  * Originally Released Under LGPL - original licence link has changed is not relivant.
11101  *
11102  * Fork - LGPL
11103  * <script type="text/javascript">
11104  */
11105
11106  
11107
11108 /**
11109  * @class Roo.data.Connection
11110  * @extends Roo.util.Observable
11111  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11112  * either to a configured URL, or to a URL specified at request time.<br><br>
11113  * <p>
11114  * Requests made by this class are asynchronous, and will return immediately. No data from
11115  * the server will be available to the statement immediately following the {@link #request} call.
11116  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11117  * <p>
11118  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11119  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11120  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11121  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11122  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11123  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11124  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11125  * standard DOM methods.
11126  * @constructor
11127  * @param {Object} config a configuration object.
11128  */
11129 Roo.data.Connection = function(config){
11130     Roo.apply(this, config);
11131     this.addEvents({
11132         /**
11133          * @event beforerequest
11134          * Fires before a network request is made to retrieve a data object.
11135          * @param {Connection} conn This Connection object.
11136          * @param {Object} options The options config object passed to the {@link #request} method.
11137          */
11138         "beforerequest" : true,
11139         /**
11140          * @event requestcomplete
11141          * Fires if the request was successfully completed.
11142          * @param {Connection} conn This Connection object.
11143          * @param {Object} response The XHR object containing the response data.
11144          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11145          * @param {Object} options The options config object passed to the {@link #request} method.
11146          */
11147         "requestcomplete" : true,
11148         /**
11149          * @event requestexception
11150          * Fires if an error HTTP status was returned from the server.
11151          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11152          * @param {Connection} conn This Connection object.
11153          * @param {Object} response The XHR object containing the response data.
11154          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11155          * @param {Object} options The options config object passed to the {@link #request} method.
11156          */
11157         "requestexception" : true
11158     });
11159     Roo.data.Connection.superclass.constructor.call(this);
11160 };
11161
11162 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11163     /**
11164      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11165      */
11166     /**
11167      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11168      * extra parameters to each request made by this object. (defaults to undefined)
11169      */
11170     /**
11171      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11172      *  to each request made by this object. (defaults to undefined)
11173      */
11174     /**
11175      * @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)
11176      */
11177     /**
11178      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11179      */
11180     timeout : 30000,
11181     /**
11182      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11183      * @type Boolean
11184      */
11185     autoAbort:false,
11186
11187     /**
11188      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11189      * @type Boolean
11190      */
11191     disableCaching: true,
11192
11193     /**
11194      * Sends an HTTP request to a remote server.
11195      * @param {Object} options An object which may contain the following properties:<ul>
11196      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11197      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11198      * request, a url encoded string or a function to call to get either.</li>
11199      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11200      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11201      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11202      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11203      * <li>options {Object} The parameter to the request call.</li>
11204      * <li>success {Boolean} True if the request succeeded.</li>
11205      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11206      * </ul></li>
11207      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11208      * The callback is passed the following parameters:<ul>
11209      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11210      * <li>options {Object} The parameter to the request call.</li>
11211      * </ul></li>
11212      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11213      * The callback is passed the following parameters:<ul>
11214      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11215      * <li>options {Object} The parameter to the request call.</li>
11216      * </ul></li>
11217      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11218      * for the callback function. Defaults to the browser window.</li>
11219      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11220      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11221      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11222      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11223      * params for the post data. Any params will be appended to the URL.</li>
11224      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11225      * </ul>
11226      * @return {Number} transactionId
11227      */
11228     request : function(o){
11229         if(this.fireEvent("beforerequest", this, o) !== false){
11230             var p = o.params;
11231
11232             if(typeof p == "function"){
11233                 p = p.call(o.scope||window, o);
11234             }
11235             if(typeof p == "object"){
11236                 p = Roo.urlEncode(o.params);
11237             }
11238             if(this.extraParams){
11239                 var extras = Roo.urlEncode(this.extraParams);
11240                 p = p ? (p + '&' + extras) : extras;
11241             }
11242
11243             var url = o.url || this.url;
11244             if(typeof url == 'function'){
11245                 url = url.call(o.scope||window, o);
11246             }
11247
11248             if(o.form){
11249                 var form = Roo.getDom(o.form);
11250                 url = url || form.action;
11251
11252                 var enctype = form.getAttribute("enctype");
11253                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11254                     return this.doFormUpload(o, p, url);
11255                 }
11256                 var f = Roo.lib.Ajax.serializeForm(form);
11257                 p = p ? (p + '&' + f) : f;
11258             }
11259
11260             var hs = o.headers;
11261             if(this.defaultHeaders){
11262                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11263                 if(!o.headers){
11264                     o.headers = hs;
11265                 }
11266             }
11267
11268             var cb = {
11269                 success: this.handleResponse,
11270                 failure: this.handleFailure,
11271                 scope: this,
11272                 argument: {options: o},
11273                 timeout : this.timeout
11274             };
11275
11276             var method = o.method||this.method||(p ? "POST" : "GET");
11277
11278             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11279                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11280             }
11281
11282             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11283                 if(o.autoAbort){
11284                     this.abort();
11285                 }
11286             }else if(this.autoAbort !== false){
11287                 this.abort();
11288             }
11289
11290             if((method == 'GET' && p) || o.xmlData){
11291                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11292                 p = '';
11293             }
11294             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11295             return this.transId;
11296         }else{
11297             Roo.callback(o.callback, o.scope, [o, null, null]);
11298             return null;
11299         }
11300     },
11301
11302     /**
11303      * Determine whether this object has a request outstanding.
11304      * @param {Number} transactionId (Optional) defaults to the last transaction
11305      * @return {Boolean} True if there is an outstanding request.
11306      */
11307     isLoading : function(transId){
11308         if(transId){
11309             return Roo.lib.Ajax.isCallInProgress(transId);
11310         }else{
11311             return this.transId ? true : false;
11312         }
11313     },
11314
11315     /**
11316      * Aborts any outstanding request.
11317      * @param {Number} transactionId (Optional) defaults to the last transaction
11318      */
11319     abort : function(transId){
11320         if(transId || this.isLoading()){
11321             Roo.lib.Ajax.abort(transId || this.transId);
11322         }
11323     },
11324
11325     // private
11326     handleResponse : function(response){
11327         this.transId = false;
11328         var options = response.argument.options;
11329         response.argument = options ? options.argument : null;
11330         this.fireEvent("requestcomplete", this, response, options);
11331         Roo.callback(options.success, options.scope, [response, options]);
11332         Roo.callback(options.callback, options.scope, [options, true, response]);
11333     },
11334
11335     // private
11336     handleFailure : function(response, e){
11337         this.transId = false;
11338         var options = response.argument.options;
11339         response.argument = options ? options.argument : null;
11340         this.fireEvent("requestexception", this, response, options, e);
11341         Roo.callback(options.failure, options.scope, [response, options]);
11342         Roo.callback(options.callback, options.scope, [options, false, response]);
11343     },
11344
11345     // private
11346     doFormUpload : function(o, ps, url){
11347         var id = Roo.id();
11348         var frame = document.createElement('iframe');
11349         frame.id = id;
11350         frame.name = id;
11351         frame.className = 'x-hidden';
11352         if(Roo.isIE){
11353             frame.src = Roo.SSL_SECURE_URL;
11354         }
11355         document.body.appendChild(frame);
11356
11357         if(Roo.isIE){
11358            document.frames[id].name = id;
11359         }
11360
11361         var form = Roo.getDom(o.form);
11362         form.target = id;
11363         form.method = 'POST';
11364         form.enctype = form.encoding = 'multipart/form-data';
11365         if(url){
11366             form.action = url;
11367         }
11368
11369         var hiddens, hd;
11370         if(ps){ // add dynamic params
11371             hiddens = [];
11372             ps = Roo.urlDecode(ps, false);
11373             for(var k in ps){
11374                 if(ps.hasOwnProperty(k)){
11375                     hd = document.createElement('input');
11376                     hd.type = 'hidden';
11377                     hd.name = k;
11378                     hd.value = ps[k];
11379                     form.appendChild(hd);
11380                     hiddens.push(hd);
11381                 }
11382             }
11383         }
11384
11385         function cb(){
11386             var r = {  // bogus response object
11387                 responseText : '',
11388                 responseXML : null
11389             };
11390
11391             r.argument = o ? o.argument : null;
11392
11393             try { //
11394                 var doc;
11395                 if(Roo.isIE){
11396                     doc = frame.contentWindow.document;
11397                 }else {
11398                     doc = (frame.contentDocument || window.frames[id].document);
11399                 }
11400                 if(doc && doc.body){
11401                     r.responseText = doc.body.innerHTML;
11402                 }
11403                 if(doc && doc.XMLDocument){
11404                     r.responseXML = doc.XMLDocument;
11405                 }else {
11406                     r.responseXML = doc;
11407                 }
11408             }
11409             catch(e) {
11410                 // ignore
11411             }
11412
11413             Roo.EventManager.removeListener(frame, 'load', cb, this);
11414
11415             this.fireEvent("requestcomplete", this, r, o);
11416             Roo.callback(o.success, o.scope, [r, o]);
11417             Roo.callback(o.callback, o.scope, [o, true, r]);
11418
11419             setTimeout(function(){document.body.removeChild(frame);}, 100);
11420         }
11421
11422         Roo.EventManager.on(frame, 'load', cb, this);
11423         form.submit();
11424
11425         if(hiddens){ // remove dynamic params
11426             for(var i = 0, len = hiddens.length; i < len; i++){
11427                 form.removeChild(hiddens[i]);
11428             }
11429         }
11430     }
11431 });
11432
11433 /**
11434  * @class Roo.Ajax
11435  * @extends Roo.data.Connection
11436  * Global Ajax request class.
11437  *
11438  * @singleton
11439  */
11440 Roo.Ajax = new Roo.data.Connection({
11441     // fix up the docs
11442    /**
11443      * @cfg {String} url @hide
11444      */
11445     /**
11446      * @cfg {Object} extraParams @hide
11447      */
11448     /**
11449      * @cfg {Object} defaultHeaders @hide
11450      */
11451     /**
11452      * @cfg {String} method (Optional) @hide
11453      */
11454     /**
11455      * @cfg {Number} timeout (Optional) @hide
11456      */
11457     /**
11458      * @cfg {Boolean} autoAbort (Optional) @hide
11459      */
11460
11461     /**
11462      * @cfg {Boolean} disableCaching (Optional) @hide
11463      */
11464
11465     /**
11466      * @property  disableCaching
11467      * True to add a unique cache-buster param to GET requests. (defaults to true)
11468      * @type Boolean
11469      */
11470     /**
11471      * @property  url
11472      * The default URL to be used for requests to the server. (defaults to undefined)
11473      * @type String
11474      */
11475     /**
11476      * @property  extraParams
11477      * An object containing properties which are used as
11478      * extra parameters to each request made by this object. (defaults to undefined)
11479      * @type Object
11480      */
11481     /**
11482      * @property  defaultHeaders
11483      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11484      * @type Object
11485      */
11486     /**
11487      * @property  method
11488      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11489      * @type String
11490      */
11491     /**
11492      * @property  timeout
11493      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11494      * @type Number
11495      */
11496
11497     /**
11498      * @property  autoAbort
11499      * Whether a new request should abort any pending requests. (defaults to false)
11500      * @type Boolean
11501      */
11502     autoAbort : false,
11503
11504     /**
11505      * Serialize the passed form into a url encoded string
11506      * @param {String/HTMLElement} form
11507      * @return {String}
11508      */
11509     serializeForm : function(form){
11510         return Roo.lib.Ajax.serializeForm(form);
11511     }
11512 });/*
11513  * Based on:
11514  * Ext JS Library 1.1.1
11515  * Copyright(c) 2006-2007, Ext JS, LLC.
11516  *
11517  * Originally Released Under LGPL - original licence link has changed is not relivant.
11518  *
11519  * Fork - LGPL
11520  * <script type="text/javascript">
11521  */
11522  
11523 /**
11524  * @class Roo.Ajax
11525  * @extends Roo.data.Connection
11526  * Global Ajax request class.
11527  *
11528  * @instanceOf  Roo.data.Connection
11529  */
11530 Roo.Ajax = new Roo.data.Connection({
11531     // fix up the docs
11532     
11533     /**
11534      * fix up scoping
11535      * @scope Roo.Ajax
11536      */
11537     
11538    /**
11539      * @cfg {String} url @hide
11540      */
11541     /**
11542      * @cfg {Object} extraParams @hide
11543      */
11544     /**
11545      * @cfg {Object} defaultHeaders @hide
11546      */
11547     /**
11548      * @cfg {String} method (Optional) @hide
11549      */
11550     /**
11551      * @cfg {Number} timeout (Optional) @hide
11552      */
11553     /**
11554      * @cfg {Boolean} autoAbort (Optional) @hide
11555      */
11556
11557     /**
11558      * @cfg {Boolean} disableCaching (Optional) @hide
11559      */
11560
11561     /**
11562      * @property  disableCaching
11563      * True to add a unique cache-buster param to GET requests. (defaults to true)
11564      * @type Boolean
11565      */
11566     /**
11567      * @property  url
11568      * The default URL to be used for requests to the server. (defaults to undefined)
11569      * @type String
11570      */
11571     /**
11572      * @property  extraParams
11573      * An object containing properties which are used as
11574      * extra parameters to each request made by this object. (defaults to undefined)
11575      * @type Object
11576      */
11577     /**
11578      * @property  defaultHeaders
11579      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11580      * @type Object
11581      */
11582     /**
11583      * @property  method
11584      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11585      * @type String
11586      */
11587     /**
11588      * @property  timeout
11589      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11590      * @type Number
11591      */
11592
11593     /**
11594      * @property  autoAbort
11595      * Whether a new request should abort any pending requests. (defaults to false)
11596      * @type Boolean
11597      */
11598     autoAbort : false,
11599
11600     /**
11601      * Serialize the passed form into a url encoded string
11602      * @param {String/HTMLElement} form
11603      * @return {String}
11604      */
11605     serializeForm : function(form){
11606         return Roo.lib.Ajax.serializeForm(form);
11607     }
11608 });/*
11609  * Based on:
11610  * Ext JS Library 1.1.1
11611  * Copyright(c) 2006-2007, Ext JS, LLC.
11612  *
11613  * Originally Released Under LGPL - original licence link has changed is not relivant.
11614  *
11615  * Fork - LGPL
11616  * <script type="text/javascript">
11617  */
11618
11619  
11620 /**
11621  * @class Roo.UpdateManager
11622  * @extends Roo.util.Observable
11623  * Provides AJAX-style update for Element object.<br><br>
11624  * Usage:<br>
11625  * <pre><code>
11626  * // Get it from a Roo.Element object
11627  * var el = Roo.get("foo");
11628  * var mgr = el.getUpdateManager();
11629  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11630  * ...
11631  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11632  * <br>
11633  * // or directly (returns the same UpdateManager instance)
11634  * var mgr = new Roo.UpdateManager("myElementId");
11635  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11636  * mgr.on("update", myFcnNeedsToKnow);
11637  * <br>
11638    // short handed call directly from the element object
11639    Roo.get("foo").load({
11640         url: "bar.php",
11641         scripts:true,
11642         params: "for=bar",
11643         text: "Loading Foo..."
11644    });
11645  * </code></pre>
11646  * @constructor
11647  * Create new UpdateManager directly.
11648  * @param {String/HTMLElement/Roo.Element} el The element to update
11649  * @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).
11650  */
11651 Roo.UpdateManager = function(el, forceNew){
11652     el = Roo.get(el);
11653     if(!forceNew && el.updateManager){
11654         return el.updateManager;
11655     }
11656     /**
11657      * The Element object
11658      * @type Roo.Element
11659      */
11660     this.el = el;
11661     /**
11662      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11663      * @type String
11664      */
11665     this.defaultUrl = null;
11666
11667     this.addEvents({
11668         /**
11669          * @event beforeupdate
11670          * Fired before an update is made, return false from your handler and the update is cancelled.
11671          * @param {Roo.Element} el
11672          * @param {String/Object/Function} url
11673          * @param {String/Object} params
11674          */
11675         "beforeupdate": true,
11676         /**
11677          * @event update
11678          * Fired after successful update is made.
11679          * @param {Roo.Element} el
11680          * @param {Object} oResponseObject The response Object
11681          */
11682         "update": true,
11683         /**
11684          * @event failure
11685          * Fired on update failure.
11686          * @param {Roo.Element} el
11687          * @param {Object} oResponseObject The response Object
11688          */
11689         "failure": true
11690     });
11691     var d = Roo.UpdateManager.defaults;
11692     /**
11693      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11694      * @type String
11695      */
11696     this.sslBlankUrl = d.sslBlankUrl;
11697     /**
11698      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11699      * @type Boolean
11700      */
11701     this.disableCaching = d.disableCaching;
11702     /**
11703      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11704      * @type String
11705      */
11706     this.indicatorText = d.indicatorText;
11707     /**
11708      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11709      * @type String
11710      */
11711     this.showLoadIndicator = d.showLoadIndicator;
11712     /**
11713      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11714      * @type Number
11715      */
11716     this.timeout = d.timeout;
11717
11718     /**
11719      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11720      * @type Boolean
11721      */
11722     this.loadScripts = d.loadScripts;
11723
11724     /**
11725      * Transaction object of current executing transaction
11726      */
11727     this.transaction = null;
11728
11729     /**
11730      * @private
11731      */
11732     this.autoRefreshProcId = null;
11733     /**
11734      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11735      * @type Function
11736      */
11737     this.refreshDelegate = this.refresh.createDelegate(this);
11738     /**
11739      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11740      * @type Function
11741      */
11742     this.updateDelegate = this.update.createDelegate(this);
11743     /**
11744      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11745      * @type Function
11746      */
11747     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11748     /**
11749      * @private
11750      */
11751     this.successDelegate = this.processSuccess.createDelegate(this);
11752     /**
11753      * @private
11754      */
11755     this.failureDelegate = this.processFailure.createDelegate(this);
11756
11757     if(!this.renderer){
11758      /**
11759       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11760       */
11761     this.renderer = new Roo.UpdateManager.BasicRenderer();
11762     }
11763     
11764     Roo.UpdateManager.superclass.constructor.call(this);
11765 };
11766
11767 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11768     /**
11769      * Get the Element this UpdateManager is bound to
11770      * @return {Roo.Element} The element
11771      */
11772     getEl : function(){
11773         return this.el;
11774     },
11775     /**
11776      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11777      * @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:
11778 <pre><code>
11779 um.update({<br/>
11780     url: "your-url.php",<br/>
11781     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11782     callback: yourFunction,<br/>
11783     scope: yourObject, //(optional scope)  <br/>
11784     discardUrl: false, <br/>
11785     nocache: false,<br/>
11786     text: "Loading...",<br/>
11787     timeout: 30,<br/>
11788     scripts: false<br/>
11789 });
11790 </code></pre>
11791      * The only required property is url. The optional properties nocache, text and scripts
11792      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11793      * @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}
11794      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11795      * @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.
11796      */
11797     update : function(url, params, callback, discardUrl){
11798         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11799             var method = this.method, cfg;
11800             if(typeof url == "object"){ // must be config object
11801                 cfg = url;
11802                 url = cfg.url;
11803                 params = params || cfg.params;
11804                 callback = callback || cfg.callback;
11805                 discardUrl = discardUrl || cfg.discardUrl;
11806                 if(callback && cfg.scope){
11807                     callback = callback.createDelegate(cfg.scope);
11808                 }
11809                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11810                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11811                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11812                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11813                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11814             }
11815             this.showLoading();
11816             if(!discardUrl){
11817                 this.defaultUrl = url;
11818             }
11819             if(typeof url == "function"){
11820                 url = url.call(this);
11821             }
11822
11823             method = method || (params ? "POST" : "GET");
11824             if(method == "GET"){
11825                 url = this.prepareUrl(url);
11826             }
11827
11828             var o = Roo.apply(cfg ||{}, {
11829                 url : url,
11830                 params: params,
11831                 success: this.successDelegate,
11832                 failure: this.failureDelegate,
11833                 callback: undefined,
11834                 timeout: (this.timeout*1000),
11835                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11836             });
11837
11838             this.transaction = Roo.Ajax.request(o);
11839         }
11840     },
11841
11842     /**
11843      * 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.
11844      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11845      * @param {String/HTMLElement} form The form Id or form element
11846      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11847      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11848      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11849      */
11850     formUpdate : function(form, url, reset, callback){
11851         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11852             if(typeof url == "function"){
11853                 url = url.call(this);
11854             }
11855             form = Roo.getDom(form);
11856             this.transaction = Roo.Ajax.request({
11857                 form: form,
11858                 url:url,
11859                 success: this.successDelegate,
11860                 failure: this.failureDelegate,
11861                 timeout: (this.timeout*1000),
11862                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11863             });
11864             this.showLoading.defer(1, this);
11865         }
11866     },
11867
11868     /**
11869      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11870      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11871      */
11872     refresh : function(callback){
11873         if(this.defaultUrl == null){
11874             return;
11875         }
11876         this.update(this.defaultUrl, null, callback, true);
11877     },
11878
11879     /**
11880      * Set this element to auto refresh.
11881      * @param {Number} interval How often to update (in seconds).
11882      * @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)
11883      * @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}
11884      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11885      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11886      */
11887     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11888         if(refreshNow){
11889             this.update(url || this.defaultUrl, params, callback, true);
11890         }
11891         if(this.autoRefreshProcId){
11892             clearInterval(this.autoRefreshProcId);
11893         }
11894         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11895     },
11896
11897     /**
11898      * Stop auto refresh on this element.
11899      */
11900      stopAutoRefresh : function(){
11901         if(this.autoRefreshProcId){
11902             clearInterval(this.autoRefreshProcId);
11903             delete this.autoRefreshProcId;
11904         }
11905     },
11906
11907     isAutoRefreshing : function(){
11908        return this.autoRefreshProcId ? true : false;
11909     },
11910     /**
11911      * Called to update the element to "Loading" state. Override to perform custom action.
11912      */
11913     showLoading : function(){
11914         if(this.showLoadIndicator){
11915             this.el.update(this.indicatorText);
11916         }
11917     },
11918
11919     /**
11920      * Adds unique parameter to query string if disableCaching = true
11921      * @private
11922      */
11923     prepareUrl : function(url){
11924         if(this.disableCaching){
11925             var append = "_dc=" + (new Date().getTime());
11926             if(url.indexOf("?") !== -1){
11927                 url += "&" + append;
11928             }else{
11929                 url += "?" + append;
11930             }
11931         }
11932         return url;
11933     },
11934
11935     /**
11936      * @private
11937      */
11938     processSuccess : function(response){
11939         this.transaction = null;
11940         if(response.argument.form && response.argument.reset){
11941             try{ // put in try/catch since some older FF releases had problems with this
11942                 response.argument.form.reset();
11943             }catch(e){}
11944         }
11945         if(this.loadScripts){
11946             this.renderer.render(this.el, response, this,
11947                 this.updateComplete.createDelegate(this, [response]));
11948         }else{
11949             this.renderer.render(this.el, response, this);
11950             this.updateComplete(response);
11951         }
11952     },
11953
11954     updateComplete : function(response){
11955         this.fireEvent("update", this.el, response);
11956         if(typeof response.argument.callback == "function"){
11957             response.argument.callback(this.el, true, response);
11958         }
11959     },
11960
11961     /**
11962      * @private
11963      */
11964     processFailure : function(response){
11965         this.transaction = null;
11966         this.fireEvent("failure", this.el, response);
11967         if(typeof response.argument.callback == "function"){
11968             response.argument.callback(this.el, false, response);
11969         }
11970     },
11971
11972     /**
11973      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11974      * @param {Object} renderer The object implementing the render() method
11975      */
11976     setRenderer : function(renderer){
11977         this.renderer = renderer;
11978     },
11979
11980     getRenderer : function(){
11981        return this.renderer;
11982     },
11983
11984     /**
11985      * Set the defaultUrl used for updates
11986      * @param {String/Function} defaultUrl The url or a function to call to get the url
11987      */
11988     setDefaultUrl : function(defaultUrl){
11989         this.defaultUrl = defaultUrl;
11990     },
11991
11992     /**
11993      * Aborts the executing transaction
11994      */
11995     abort : function(){
11996         if(this.transaction){
11997             Roo.Ajax.abort(this.transaction);
11998         }
11999     },
12000
12001     /**
12002      * Returns true if an update is in progress
12003      * @return {Boolean}
12004      */
12005     isUpdating : function(){
12006         if(this.transaction){
12007             return Roo.Ajax.isLoading(this.transaction);
12008         }
12009         return false;
12010     }
12011 });
12012
12013 /**
12014  * @class Roo.UpdateManager.defaults
12015  * @static (not really - but it helps the doc tool)
12016  * The defaults collection enables customizing the default properties of UpdateManager
12017  */
12018    Roo.UpdateManager.defaults = {
12019        /**
12020          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12021          * @type Number
12022          */
12023          timeout : 30,
12024
12025          /**
12026          * True to process scripts by default (Defaults to false).
12027          * @type Boolean
12028          */
12029         loadScripts : false,
12030
12031         /**
12032         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12033         * @type String
12034         */
12035         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12036         /**
12037          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12038          * @type Boolean
12039          */
12040         disableCaching : false,
12041         /**
12042          * Whether to show indicatorText when loading (Defaults to true).
12043          * @type Boolean
12044          */
12045         showLoadIndicator : true,
12046         /**
12047          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12048          * @type String
12049          */
12050         indicatorText : '<div class="loading-indicator">Loading...</div>'
12051    };
12052
12053 /**
12054  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12055  *Usage:
12056  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12057  * @param {String/HTMLElement/Roo.Element} el The element to update
12058  * @param {String} url The url
12059  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12060  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12061  * @static
12062  * @deprecated
12063  * @member Roo.UpdateManager
12064  */
12065 Roo.UpdateManager.updateElement = function(el, url, params, options){
12066     var um = Roo.get(el, true).getUpdateManager();
12067     Roo.apply(um, options);
12068     um.update(url, params, options ? options.callback : null);
12069 };
12070 // alias for backwards compat
12071 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12072 /**
12073  * @class Roo.UpdateManager.BasicRenderer
12074  * Default Content renderer. Updates the elements innerHTML with the responseText.
12075  */
12076 Roo.UpdateManager.BasicRenderer = function(){};
12077
12078 Roo.UpdateManager.BasicRenderer.prototype = {
12079     /**
12080      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12081      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12082      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12083      * @param {Roo.Element} el The element being rendered
12084      * @param {Object} response The YUI Connect response object
12085      * @param {UpdateManager} updateManager The calling update manager
12086      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12087      */
12088      render : function(el, response, updateManager, callback){
12089         el.update(response.responseText, updateManager.loadScripts, callback);
12090     }
12091 };
12092 /*
12093  * Based on:
12094  * Ext JS Library 1.1.1
12095  * Copyright(c) 2006-2007, Ext JS, LLC.
12096  *
12097  * Originally Released Under LGPL - original licence link has changed is not relivant.
12098  *
12099  * Fork - LGPL
12100  * <script type="text/javascript">
12101  */
12102
12103 /**
12104  * @class Roo.util.DelayedTask
12105  * Provides a convenient method of performing setTimeout where a new
12106  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12107  * You can use this class to buffer
12108  * the keypress events for a certain number of milliseconds, and perform only if they stop
12109  * for that amount of time.
12110  * @constructor The parameters to this constructor serve as defaults and are not required.
12111  * @param {Function} fn (optional) The default function to timeout
12112  * @param {Object} scope (optional) The default scope of that timeout
12113  * @param {Array} args (optional) The default Array of arguments
12114  */
12115 Roo.util.DelayedTask = function(fn, scope, args){
12116     var id = null, d, t;
12117
12118     var call = function(){
12119         var now = new Date().getTime();
12120         if(now - t >= d){
12121             clearInterval(id);
12122             id = null;
12123             fn.apply(scope, args || []);
12124         }
12125     };
12126     /**
12127      * Cancels any pending timeout and queues a new one
12128      * @param {Number} delay The milliseconds to delay
12129      * @param {Function} newFn (optional) Overrides function passed to constructor
12130      * @param {Object} newScope (optional) Overrides scope passed to constructor
12131      * @param {Array} newArgs (optional) Overrides args passed to constructor
12132      */
12133     this.delay = function(delay, newFn, newScope, newArgs){
12134         if(id && delay != d){
12135             this.cancel();
12136         }
12137         d = delay;
12138         t = new Date().getTime();
12139         fn = newFn || fn;
12140         scope = newScope || scope;
12141         args = newArgs || args;
12142         if(!id){
12143             id = setInterval(call, d);
12144         }
12145     };
12146
12147     /**
12148      * Cancel the last queued timeout
12149      */
12150     this.cancel = function(){
12151         if(id){
12152             clearInterval(id);
12153             id = null;
12154         }
12155     };
12156 };/*
12157  * Based on:
12158  * Ext JS Library 1.1.1
12159  * Copyright(c) 2006-2007, Ext JS, LLC.
12160  *
12161  * Originally Released Under LGPL - original licence link has changed is not relivant.
12162  *
12163  * Fork - LGPL
12164  * <script type="text/javascript">
12165  */
12166  
12167  
12168 Roo.util.TaskRunner = function(interval){
12169     interval = interval || 10;
12170     var tasks = [], removeQueue = [];
12171     var id = 0;
12172     var running = false;
12173
12174     var stopThread = function(){
12175         running = false;
12176         clearInterval(id);
12177         id = 0;
12178     };
12179
12180     var startThread = function(){
12181         if(!running){
12182             running = true;
12183             id = setInterval(runTasks, interval);
12184         }
12185     };
12186
12187     var removeTask = function(task){
12188         removeQueue.push(task);
12189         if(task.onStop){
12190             task.onStop();
12191         }
12192     };
12193
12194     var runTasks = function(){
12195         if(removeQueue.length > 0){
12196             for(var i = 0, len = removeQueue.length; i < len; i++){
12197                 tasks.remove(removeQueue[i]);
12198             }
12199             removeQueue = [];
12200             if(tasks.length < 1){
12201                 stopThread();
12202                 return;
12203             }
12204         }
12205         var now = new Date().getTime();
12206         for(var i = 0, len = tasks.length; i < len; ++i){
12207             var t = tasks[i];
12208             var itime = now - t.taskRunTime;
12209             if(t.interval <= itime){
12210                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12211                 t.taskRunTime = now;
12212                 if(rt === false || t.taskRunCount === t.repeat){
12213                     removeTask(t);
12214                     return;
12215                 }
12216             }
12217             if(t.duration && t.duration <= (now - t.taskStartTime)){
12218                 removeTask(t);
12219             }
12220         }
12221     };
12222
12223     /**
12224      * Queues a new task.
12225      * @param {Object} task
12226      */
12227     this.start = function(task){
12228         tasks.push(task);
12229         task.taskStartTime = new Date().getTime();
12230         task.taskRunTime = 0;
12231         task.taskRunCount = 0;
12232         startThread();
12233         return task;
12234     };
12235
12236     this.stop = function(task){
12237         removeTask(task);
12238         return task;
12239     };
12240
12241     this.stopAll = function(){
12242         stopThread();
12243         for(var i = 0, len = tasks.length; i < len; i++){
12244             if(tasks[i].onStop){
12245                 tasks[i].onStop();
12246             }
12247         }
12248         tasks = [];
12249         removeQueue = [];
12250     };
12251 };
12252
12253 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12254  * Based on:
12255  * Ext JS Library 1.1.1
12256  * Copyright(c) 2006-2007, Ext JS, LLC.
12257  *
12258  * Originally Released Under LGPL - original licence link has changed is not relivant.
12259  *
12260  * Fork - LGPL
12261  * <script type="text/javascript">
12262  */
12263
12264  
12265 /**
12266  * @class Roo.util.MixedCollection
12267  * @extends Roo.util.Observable
12268  * A Collection class that maintains both numeric indexes and keys and exposes events.
12269  * @constructor
12270  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12271  * collection (defaults to false)
12272  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12273  * and return the key value for that item.  This is used when available to look up the key on items that
12274  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12275  * equivalent to providing an implementation for the {@link #getKey} method.
12276  */
12277 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12278     this.items = [];
12279     this.map = {};
12280     this.keys = [];
12281     this.length = 0;
12282     this.addEvents({
12283         /**
12284          * @event clear
12285          * Fires when the collection is cleared.
12286          */
12287         "clear" : true,
12288         /**
12289          * @event add
12290          * Fires when an item is added to the collection.
12291          * @param {Number} index The index at which the item was added.
12292          * @param {Object} o The item added.
12293          * @param {String} key The key associated with the added item.
12294          */
12295         "add" : true,
12296         /**
12297          * @event replace
12298          * Fires when an item is replaced in the collection.
12299          * @param {String} key he key associated with the new added.
12300          * @param {Object} old The item being replaced.
12301          * @param {Object} new The new item.
12302          */
12303         "replace" : true,
12304         /**
12305          * @event remove
12306          * Fires when an item is removed from the collection.
12307          * @param {Object} o The item being removed.
12308          * @param {String} key (optional) The key associated with the removed item.
12309          */
12310         "remove" : true,
12311         "sort" : true
12312     });
12313     this.allowFunctions = allowFunctions === true;
12314     if(keyFn){
12315         this.getKey = keyFn;
12316     }
12317     Roo.util.MixedCollection.superclass.constructor.call(this);
12318 };
12319
12320 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12321     allowFunctions : false,
12322     
12323 /**
12324  * Adds an item to the collection.
12325  * @param {String} key The key to associate with the item
12326  * @param {Object} o The item to add.
12327  * @return {Object} The item added.
12328  */
12329     add : function(key, o){
12330         if(arguments.length == 1){
12331             o = arguments[0];
12332             key = this.getKey(o);
12333         }
12334         if(typeof key == "undefined" || key === null){
12335             this.length++;
12336             this.items.push(o);
12337             this.keys.push(null);
12338         }else{
12339             var old = this.map[key];
12340             if(old){
12341                 return this.replace(key, o);
12342             }
12343             this.length++;
12344             this.items.push(o);
12345             this.map[key] = o;
12346             this.keys.push(key);
12347         }
12348         this.fireEvent("add", this.length-1, o, key);
12349         return o;
12350     },
12351        
12352 /**
12353   * MixedCollection has a generic way to fetch keys if you implement getKey.
12354 <pre><code>
12355 // normal way
12356 var mc = new Roo.util.MixedCollection();
12357 mc.add(someEl.dom.id, someEl);
12358 mc.add(otherEl.dom.id, otherEl);
12359 //and so on
12360
12361 // using getKey
12362 var mc = new Roo.util.MixedCollection();
12363 mc.getKey = function(el){
12364    return el.dom.id;
12365 };
12366 mc.add(someEl);
12367 mc.add(otherEl);
12368
12369 // or via the constructor
12370 var mc = new Roo.util.MixedCollection(false, function(el){
12371    return el.dom.id;
12372 });
12373 mc.add(someEl);
12374 mc.add(otherEl);
12375 </code></pre>
12376  * @param o {Object} The item for which to find the key.
12377  * @return {Object} The key for the passed item.
12378  */
12379     getKey : function(o){
12380          return o.id; 
12381     },
12382    
12383 /**
12384  * Replaces an item in the collection.
12385  * @param {String} key The key associated with the item to replace, or the item to replace.
12386  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12387  * @return {Object}  The new item.
12388  */
12389     replace : function(key, o){
12390         if(arguments.length == 1){
12391             o = arguments[0];
12392             key = this.getKey(o);
12393         }
12394         var old = this.item(key);
12395         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12396              return this.add(key, o);
12397         }
12398         var index = this.indexOfKey(key);
12399         this.items[index] = o;
12400         this.map[key] = o;
12401         this.fireEvent("replace", key, old, o);
12402         return o;
12403     },
12404    
12405 /**
12406  * Adds all elements of an Array or an Object to the collection.
12407  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12408  * an Array of values, each of which are added to the collection.
12409  */
12410     addAll : function(objs){
12411         if(arguments.length > 1 || objs instanceof Array){
12412             var args = arguments.length > 1 ? arguments : objs;
12413             for(var i = 0, len = args.length; i < len; i++){
12414                 this.add(args[i]);
12415             }
12416         }else{
12417             for(var key in objs){
12418                 if(this.allowFunctions || typeof objs[key] != "function"){
12419                     this.add(key, objs[key]);
12420                 }
12421             }
12422         }
12423     },
12424    
12425 /**
12426  * Executes the specified function once for every item in the collection, passing each
12427  * item as the first and only parameter. returning false from the function will stop the iteration.
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     each : function(fn, scope){
12432         var items = [].concat(this.items); // each safe for removal
12433         for(var i = 0, len = items.length; i < len; i++){
12434             if(fn.call(scope || items[i], items[i], i, len) === false){
12435                 break;
12436             }
12437         }
12438     },
12439    
12440 /**
12441  * Executes the specified function once for every key in the collection, passing each
12442  * key, and its associated item as the first two parameters.
12443  * @param {Function} fn The function to execute for each item.
12444  * @param {Object} scope (optional) The scope in which to execute the function.
12445  */
12446     eachKey : function(fn, scope){
12447         for(var i = 0, len = this.keys.length; i < len; i++){
12448             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12449         }
12450     },
12451    
12452 /**
12453  * Returns the first item in the collection which elicits a true return value from the
12454  * passed selection function.
12455  * @param {Function} fn The selection function to execute for each item.
12456  * @param {Object} scope (optional) The scope in which to execute the function.
12457  * @return {Object} The first item in the collection which returned true from the selection function.
12458  */
12459     find : function(fn, scope){
12460         for(var i = 0, len = this.items.length; i < len; i++){
12461             if(fn.call(scope || window, this.items[i], this.keys[i])){
12462                 return this.items[i];
12463             }
12464         }
12465         return null;
12466     },
12467    
12468 /**
12469  * Inserts an item at the specified index in the collection.
12470  * @param {Number} index The index to insert the item at.
12471  * @param {String} key The key to associate with the new item, or the item itself.
12472  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12473  * @return {Object} The item inserted.
12474  */
12475     insert : function(index, key, o){
12476         if(arguments.length == 2){
12477             o = arguments[1];
12478             key = this.getKey(o);
12479         }
12480         if(index >= this.length){
12481             return this.add(key, o);
12482         }
12483         this.length++;
12484         this.items.splice(index, 0, o);
12485         if(typeof key != "undefined" && key != null){
12486             this.map[key] = o;
12487         }
12488         this.keys.splice(index, 0, key);
12489         this.fireEvent("add", index, o, key);
12490         return o;
12491     },
12492    
12493 /**
12494  * Removed an item from the collection.
12495  * @param {Object} o The item to remove.
12496  * @return {Object} The item removed.
12497  */
12498     remove : function(o){
12499         return this.removeAt(this.indexOf(o));
12500     },
12501    
12502 /**
12503  * Remove an item from a specified index in the collection.
12504  * @param {Number} index The index within the collection of the item to remove.
12505  */
12506     removeAt : function(index){
12507         if(index < this.length && index >= 0){
12508             this.length--;
12509             var o = this.items[index];
12510             this.items.splice(index, 1);
12511             var key = this.keys[index];
12512             if(typeof key != "undefined"){
12513                 delete this.map[key];
12514             }
12515             this.keys.splice(index, 1);
12516             this.fireEvent("remove", o, key);
12517         }
12518     },
12519    
12520 /**
12521  * Removed an item associated with the passed key fom the collection.
12522  * @param {String} key The key of the item to remove.
12523  */
12524     removeKey : function(key){
12525         return this.removeAt(this.indexOfKey(key));
12526     },
12527    
12528 /**
12529  * Returns the number of items in the collection.
12530  * @return {Number} the number of items in the collection.
12531  */
12532     getCount : function(){
12533         return this.length; 
12534     },
12535    
12536 /**
12537  * Returns index within the collection of the passed Object.
12538  * @param {Object} o The item to find the index of.
12539  * @return {Number} index of the item.
12540  */
12541     indexOf : function(o){
12542         if(!this.items.indexOf){
12543             for(var i = 0, len = this.items.length; i < len; i++){
12544                 if(this.items[i] == o) return i;
12545             }
12546             return -1;
12547         }else{
12548             return this.items.indexOf(o);
12549         }
12550     },
12551    
12552 /**
12553  * Returns index within the collection of the passed key.
12554  * @param {String} key The key to find the index of.
12555  * @return {Number} index of the key.
12556  */
12557     indexOfKey : function(key){
12558         if(!this.keys.indexOf){
12559             for(var i = 0, len = this.keys.length; i < len; i++){
12560                 if(this.keys[i] == key) return i;
12561             }
12562             return -1;
12563         }else{
12564             return this.keys.indexOf(key);
12565         }
12566     },
12567    
12568 /**
12569  * Returns the item associated with the passed key OR index. Key has priority over index.
12570  * @param {String/Number} key The key or index of the item.
12571  * @return {Object} The item associated with the passed key.
12572  */
12573     item : function(key){
12574         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12575         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12576     },
12577     
12578 /**
12579  * Returns the item at the specified index.
12580  * @param {Number} index The index of the item.
12581  * @return {Object}
12582  */
12583     itemAt : function(index){
12584         return this.items[index];
12585     },
12586     
12587 /**
12588  * Returns the item associated with the passed key.
12589  * @param {String/Number} key The key of the item.
12590  * @return {Object} The item associated with the passed key.
12591  */
12592     key : function(key){
12593         return this.map[key];
12594     },
12595    
12596 /**
12597  * Returns true if the collection contains the passed Object as an item.
12598  * @param {Object} o  The Object to look for in the collection.
12599  * @return {Boolean} True if the collection contains the Object as an item.
12600  */
12601     contains : function(o){
12602         return this.indexOf(o) != -1;
12603     },
12604    
12605 /**
12606  * Returns true if the collection contains the passed Object as a key.
12607  * @param {String} key The key to look for in the collection.
12608  * @return {Boolean} True if the collection contains the Object as a key.
12609  */
12610     containsKey : function(key){
12611         return typeof this.map[key] != "undefined";
12612     },
12613    
12614 /**
12615  * Removes all items from the collection.
12616  */
12617     clear : function(){
12618         this.length = 0;
12619         this.items = [];
12620         this.keys = [];
12621         this.map = {};
12622         this.fireEvent("clear");
12623     },
12624    
12625 /**
12626  * Returns the first item in the collection.
12627  * @return {Object} the first item in the collection..
12628  */
12629     first : function(){
12630         return this.items[0]; 
12631     },
12632    
12633 /**
12634  * Returns the last item in the collection.
12635  * @return {Object} the last item in the collection..
12636  */
12637     last : function(){
12638         return this.items[this.length-1];   
12639     },
12640     
12641     _sort : function(property, dir, fn){
12642         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12643         fn = fn || function(a, b){
12644             return a-b;
12645         };
12646         var c = [], k = this.keys, items = this.items;
12647         for(var i = 0, len = items.length; i < len; i++){
12648             c[c.length] = {key: k[i], value: items[i], index: i};
12649         }
12650         c.sort(function(a, b){
12651             var v = fn(a[property], b[property]) * dsc;
12652             if(v == 0){
12653                 v = (a.index < b.index ? -1 : 1);
12654             }
12655             return v;
12656         });
12657         for(var i = 0, len = c.length; i < len; i++){
12658             items[i] = c[i].value;
12659             k[i] = c[i].key;
12660         }
12661         this.fireEvent("sort", this);
12662     },
12663     
12664     /**
12665      * Sorts this collection with the passed comparison function
12666      * @param {String} direction (optional) "ASC" or "DESC"
12667      * @param {Function} fn (optional) comparison function
12668      */
12669     sort : function(dir, fn){
12670         this._sort("value", dir, fn);
12671     },
12672     
12673     /**
12674      * Sorts this collection by keys
12675      * @param {String} direction (optional) "ASC" or "DESC"
12676      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12677      */
12678     keySort : function(dir, fn){
12679         this._sort("key", dir, fn || function(a, b){
12680             return String(a).toUpperCase()-String(b).toUpperCase();
12681         });
12682     },
12683     
12684     /**
12685      * Returns a range of items in this collection
12686      * @param {Number} startIndex (optional) defaults to 0
12687      * @param {Number} endIndex (optional) default to the last item
12688      * @return {Array} An array of items
12689      */
12690     getRange : function(start, end){
12691         var items = this.items;
12692         if(items.length < 1){
12693             return [];
12694         }
12695         start = start || 0;
12696         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12697         var r = [];
12698         if(start <= end){
12699             for(var i = start; i <= end; i++) {
12700                     r[r.length] = items[i];
12701             }
12702         }else{
12703             for(var i = start; i >= end; i--) {
12704                     r[r.length] = items[i];
12705             }
12706         }
12707         return r;
12708     },
12709         
12710     /**
12711      * Filter the <i>objects</i> in this collection by a specific property. 
12712      * Returns a new collection that has been filtered.
12713      * @param {String} property A property on your objects
12714      * @param {String/RegExp} value Either string that the property values 
12715      * should start with or a RegExp to test against the property
12716      * @return {MixedCollection} The new filtered collection
12717      */
12718     filter : function(property, value){
12719         if(!value.exec){ // not a regex
12720             value = String(value);
12721             if(value.length == 0){
12722                 return this.clone();
12723             }
12724             value = new RegExp("^" + Roo.escapeRe(value), "i");
12725         }
12726         return this.filterBy(function(o){
12727             return o && value.test(o[property]);
12728         });
12729         },
12730     
12731     /**
12732      * Filter by a function. * Returns a new collection that has been filtered.
12733      * The passed function will be called with each 
12734      * object in the collection. If the function returns true, the value is included 
12735      * otherwise it is filtered.
12736      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12737      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12738      * @return {MixedCollection} The new filtered collection
12739      */
12740     filterBy : function(fn, scope){
12741         var r = new Roo.util.MixedCollection();
12742         r.getKey = this.getKey;
12743         var k = this.keys, it = this.items;
12744         for(var i = 0, len = it.length; i < len; i++){
12745             if(fn.call(scope||this, it[i], k[i])){
12746                                 r.add(k[i], it[i]);
12747                         }
12748         }
12749         return r;
12750     },
12751     
12752     /**
12753      * Creates a duplicate of this collection
12754      * @return {MixedCollection}
12755      */
12756     clone : function(){
12757         var r = new Roo.util.MixedCollection();
12758         var k = this.keys, it = this.items;
12759         for(var i = 0, len = it.length; i < len; i++){
12760             r.add(k[i], it[i]);
12761         }
12762         r.getKey = this.getKey;
12763         return r;
12764     }
12765 });
12766 /**
12767  * Returns the item associated with the passed key or index.
12768  * @method
12769  * @param {String/Number} key The key or index of the item.
12770  * @return {Object} The item associated with the passed key.
12771  */
12772 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12773  * Based on:
12774  * Ext JS Library 1.1.1
12775  * Copyright(c) 2006-2007, Ext JS, LLC.
12776  *
12777  * Originally Released Under LGPL - original licence link has changed is not relivant.
12778  *
12779  * Fork - LGPL
12780  * <script type="text/javascript">
12781  */
12782 /**
12783  * @class Roo.util.JSON
12784  * Modified version of Douglas Crockford"s json.js that doesn"t
12785  * mess with the Object prototype 
12786  * http://www.json.org/js.html
12787  * @singleton
12788  */
12789 Roo.util.JSON = new (function(){
12790     var useHasOwn = {}.hasOwnProperty ? true : false;
12791     
12792     // crashes Safari in some instances
12793     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12794     
12795     var pad = function(n) {
12796         return n < 10 ? "0" + n : n;
12797     };
12798     
12799     var m = {
12800         "\b": '\\b',
12801         "\t": '\\t',
12802         "\n": '\\n',
12803         "\f": '\\f',
12804         "\r": '\\r',
12805         '"' : '\\"',
12806         "\\": '\\\\'
12807     };
12808
12809     var encodeString = function(s){
12810         if (/["\\\x00-\x1f]/.test(s)) {
12811             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12812                 var c = m[b];
12813                 if(c){
12814                     return c;
12815                 }
12816                 c = b.charCodeAt();
12817                 return "\\u00" +
12818                     Math.floor(c / 16).toString(16) +
12819                     (c % 16).toString(16);
12820             }) + '"';
12821         }
12822         return '"' + s + '"';
12823     };
12824     
12825     var encodeArray = function(o){
12826         var a = ["["], b, i, l = o.length, v;
12827             for (i = 0; i < l; i += 1) {
12828                 v = o[i];
12829                 switch (typeof v) {
12830                     case "undefined":
12831                     case "function":
12832                     case "unknown":
12833                         break;
12834                     default:
12835                         if (b) {
12836                             a.push(',');
12837                         }
12838                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12839                         b = true;
12840                 }
12841             }
12842             a.push("]");
12843             return a.join("");
12844     };
12845     
12846     var encodeDate = function(o){
12847         return '"' + o.getFullYear() + "-" +
12848                 pad(o.getMonth() + 1) + "-" +
12849                 pad(o.getDate()) + "T" +
12850                 pad(o.getHours()) + ":" +
12851                 pad(o.getMinutes()) + ":" +
12852                 pad(o.getSeconds()) + '"';
12853     };
12854     
12855     /**
12856      * Encodes an Object, Array or other value
12857      * @param {Mixed} o The variable to encode
12858      * @return {String} The JSON string
12859      */
12860     this.encode = function(o)
12861     {
12862         // should this be extended to fully wrap stringify..
12863         
12864         if(typeof o == "undefined" || o === null){
12865             return "null";
12866         }else if(o instanceof Array){
12867             return encodeArray(o);
12868         }else if(o instanceof Date){
12869             return encodeDate(o);
12870         }else if(typeof o == "string"){
12871             return encodeString(o);
12872         }else if(typeof o == "number"){
12873             return isFinite(o) ? String(o) : "null";
12874         }else if(typeof o == "boolean"){
12875             return String(o);
12876         }else {
12877             var a = ["{"], b, i, v;
12878             for (i in o) {
12879                 if(!useHasOwn || o.hasOwnProperty(i)) {
12880                     v = o[i];
12881                     switch (typeof v) {
12882                     case "undefined":
12883                     case "function":
12884                     case "unknown":
12885                         break;
12886                     default:
12887                         if(b){
12888                             a.push(',');
12889                         }
12890                         a.push(this.encode(i), ":",
12891                                 v === null ? "null" : this.encode(v));
12892                         b = true;
12893                     }
12894                 }
12895             }
12896             a.push("}");
12897             return a.join("");
12898         }
12899     };
12900     
12901     /**
12902      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12903      * @param {String} json The JSON string
12904      * @return {Object} The resulting object
12905      */
12906     this.decode = function(json){
12907         
12908         return  /** eval:var:json */ eval("(" + json + ')');
12909     };
12910 })();
12911 /** 
12912  * Shorthand for {@link Roo.util.JSON#encode}
12913  * @member Roo encode 
12914  * @method */
12915 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12916 /** 
12917  * Shorthand for {@link Roo.util.JSON#decode}
12918  * @member Roo decode 
12919  * @method */
12920 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12921 /*
12922  * Based on:
12923  * Ext JS Library 1.1.1
12924  * Copyright(c) 2006-2007, Ext JS, LLC.
12925  *
12926  * Originally Released Under LGPL - original licence link has changed is not relivant.
12927  *
12928  * Fork - LGPL
12929  * <script type="text/javascript">
12930  */
12931  
12932 /**
12933  * @class Roo.util.Format
12934  * Reusable data formatting functions
12935  * @singleton
12936  */
12937 Roo.util.Format = function(){
12938     var trimRe = /^\s+|\s+$/g;
12939     return {
12940         /**
12941          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12942          * @param {String} value The string to truncate
12943          * @param {Number} length The maximum length to allow before truncating
12944          * @return {String} The converted text
12945          */
12946         ellipsis : function(value, len){
12947             if(value && value.length > len){
12948                 return value.substr(0, len-3)+"...";
12949             }
12950             return value;
12951         },
12952
12953         /**
12954          * Checks a reference and converts it to empty string if it is undefined
12955          * @param {Mixed} value Reference to check
12956          * @return {Mixed} Empty string if converted, otherwise the original value
12957          */
12958         undef : function(value){
12959             return typeof value != "undefined" ? value : "";
12960         },
12961
12962         /**
12963          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12964          * @param {String} value The string to encode
12965          * @return {String} The encoded text
12966          */
12967         htmlEncode : function(value){
12968             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12969         },
12970
12971         /**
12972          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12973          * @param {String} value The string to decode
12974          * @return {String} The decoded text
12975          */
12976         htmlDecode : function(value){
12977             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12978         },
12979
12980         /**
12981          * Trims any whitespace from either side of a string
12982          * @param {String} value The text to trim
12983          * @return {String} The trimmed text
12984          */
12985         trim : function(value){
12986             return String(value).replace(trimRe, "");
12987         },
12988
12989         /**
12990          * Returns a substring from within an original string
12991          * @param {String} value The original text
12992          * @param {Number} start The start index of the substring
12993          * @param {Number} length The length of the substring
12994          * @return {String} The substring
12995          */
12996         substr : function(value, start, length){
12997             return String(value).substr(start, length);
12998         },
12999
13000         /**
13001          * Converts a string to all lower case letters
13002          * @param {String} value The text to convert
13003          * @return {String} The converted text
13004          */
13005         lowercase : function(value){
13006             return String(value).toLowerCase();
13007         },
13008
13009         /**
13010          * Converts a string to all upper case letters
13011          * @param {String} value The text to convert
13012          * @return {String} The converted text
13013          */
13014         uppercase : function(value){
13015             return String(value).toUpperCase();
13016         },
13017
13018         /**
13019          * Converts the first character only of a string to upper case
13020          * @param {String} value The text to convert
13021          * @return {String} The converted text
13022          */
13023         capitalize : function(value){
13024             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13025         },
13026
13027         // private
13028         call : function(value, fn){
13029             if(arguments.length > 2){
13030                 var args = Array.prototype.slice.call(arguments, 2);
13031                 args.unshift(value);
13032                  
13033                 return /** eval:var:value */  eval(fn).apply(window, args);
13034             }else{
13035                 /** eval:var:value */
13036                 return /** eval:var:value */ eval(fn).call(window, value);
13037             }
13038         },
13039
13040        
13041         /**
13042          * safer version of Math.toFixed..??/
13043          * @param {Number/String} value The numeric value to format
13044          * @param {Number/String} value Decimal places 
13045          * @return {String} The formatted currency string
13046          */
13047         toFixed : function(v, n)
13048         {
13049             // why not use to fixed - precision is buggered???
13050             if (!n) {
13051                 return Math.round(v-0);
13052             }
13053             var fact = Math.pow(10,n+1);
13054             v = (Math.round((v-0)*fact))/fact;
13055             var z = (''+fact).substring(2);
13056             if (v == Math.floor(v)) {
13057                 return Math.floor(v) + '.' + z;
13058             }
13059             
13060             // now just padd decimals..
13061             var ps = String(v).split('.');
13062             var fd = (ps[1] + z);
13063             var r = fd.substring(0,n); 
13064             var rm = fd.substring(n); 
13065             if (rm < 5) {
13066                 return ps[0] + '.' + r;
13067             }
13068             r*=1; // turn it into a number;
13069             r++;
13070             if (String(r).length != n) {
13071                 ps[0]*=1;
13072                 ps[0]++;
13073                 r = String(r).substring(1); // chop the end off.
13074             }
13075             
13076             return ps[0] + '.' + r;
13077              
13078         },
13079         
13080         /**
13081          * Format a number as US currency
13082          * @param {Number/String} value The numeric value to format
13083          * @return {String} The formatted currency string
13084          */
13085         usMoney : function(v){
13086             v = (Math.round((v-0)*100))/100;
13087             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13088             v = String(v);
13089             var ps = v.split('.');
13090             var whole = ps[0];
13091             var sub = ps[1] ? '.'+ ps[1] : '.00';
13092             var r = /(\d+)(\d{3})/;
13093             while (r.test(whole)) {
13094                 whole = whole.replace(r, '$1' + ',' + '$2');
13095             }
13096             return "$" + whole + sub ;
13097         },
13098         
13099         /**
13100          * Parse a value into a formatted date using the specified format pattern.
13101          * @param {Mixed} value The value to format
13102          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13103          * @return {String} The formatted date string
13104          */
13105         date : function(v, format){
13106             if(!v){
13107                 return "";
13108             }
13109             if(!(v instanceof Date)){
13110                 v = new Date(Date.parse(v));
13111             }
13112             return v.dateFormat(format || "m/d/Y");
13113         },
13114
13115         /**
13116          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13117          * @param {String} format Any valid date format string
13118          * @return {Function} The date formatting function
13119          */
13120         dateRenderer : function(format){
13121             return function(v){
13122                 return Roo.util.Format.date(v, format);  
13123             };
13124         },
13125
13126         // private
13127         stripTagsRE : /<\/?[^>]+>/gi,
13128         
13129         /**
13130          * Strips all HTML tags
13131          * @param {Mixed} value The text from which to strip tags
13132          * @return {String} The stripped text
13133          */
13134         stripTags : function(v){
13135             return !v ? v : String(v).replace(this.stripTagsRE, "");
13136         }
13137     };
13138 }();/*
13139  * Based on:
13140  * Ext JS Library 1.1.1
13141  * Copyright(c) 2006-2007, Ext JS, LLC.
13142  *
13143  * Originally Released Under LGPL - original licence link has changed is not relivant.
13144  *
13145  * Fork - LGPL
13146  * <script type="text/javascript">
13147  */
13148
13149
13150  
13151
13152 /**
13153  * @class Roo.MasterTemplate
13154  * @extends Roo.Template
13155  * Provides a template that can have child templates. The syntax is:
13156 <pre><code>
13157 var t = new Roo.MasterTemplate(
13158         '&lt;select name="{name}"&gt;',
13159                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13160         '&lt;/select&gt;'
13161 );
13162 t.add('options', {value: 'foo', text: 'bar'});
13163 // or you can add multiple child elements in one shot
13164 t.addAll('options', [
13165     {value: 'foo', text: 'bar'},
13166     {value: 'foo2', text: 'bar2'},
13167     {value: 'foo3', text: 'bar3'}
13168 ]);
13169 // then append, applying the master template values
13170 t.append('my-form', {name: 'my-select'});
13171 </code></pre>
13172 * A name attribute for the child template is not required if you have only one child
13173 * template or you want to refer to them by index.
13174  */
13175 Roo.MasterTemplate = function(){
13176     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13177     this.originalHtml = this.html;
13178     var st = {};
13179     var m, re = this.subTemplateRe;
13180     re.lastIndex = 0;
13181     var subIndex = 0;
13182     while(m = re.exec(this.html)){
13183         var name = m[1], content = m[2];
13184         st[subIndex] = {
13185             name: name,
13186             index: subIndex,
13187             buffer: [],
13188             tpl : new Roo.Template(content)
13189         };
13190         if(name){
13191             st[name] = st[subIndex];
13192         }
13193         st[subIndex].tpl.compile();
13194         st[subIndex].tpl.call = this.call.createDelegate(this);
13195         subIndex++;
13196     }
13197     this.subCount = subIndex;
13198     this.subs = st;
13199 };
13200 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13201     /**
13202     * The regular expression used to match sub templates
13203     * @type RegExp
13204     * @property
13205     */
13206     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13207
13208     /**
13209      * Applies the passed values to a child template.
13210      * @param {String/Number} name (optional) The name or index of the child template
13211      * @param {Array/Object} values The values to be applied to the template
13212      * @return {MasterTemplate} this
13213      */
13214      add : function(name, values){
13215         if(arguments.length == 1){
13216             values = arguments[0];
13217             name = 0;
13218         }
13219         var s = this.subs[name];
13220         s.buffer[s.buffer.length] = s.tpl.apply(values);
13221         return this;
13222     },
13223
13224     /**
13225      * Applies all the passed values to a child template.
13226      * @param {String/Number} name (optional) The name or index of the child template
13227      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13228      * @param {Boolean} reset (optional) True to reset the template first
13229      * @return {MasterTemplate} this
13230      */
13231     fill : function(name, values, reset){
13232         var a = arguments;
13233         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13234             values = a[0];
13235             name = 0;
13236             reset = a[1];
13237         }
13238         if(reset){
13239             this.reset();
13240         }
13241         for(var i = 0, len = values.length; i < len; i++){
13242             this.add(name, values[i]);
13243         }
13244         return this;
13245     },
13246
13247     /**
13248      * Resets the template for reuse
13249      * @return {MasterTemplate} this
13250      */
13251      reset : function(){
13252         var s = this.subs;
13253         for(var i = 0; i < this.subCount; i++){
13254             s[i].buffer = [];
13255         }
13256         return this;
13257     },
13258
13259     applyTemplate : function(values){
13260         var s = this.subs;
13261         var replaceIndex = -1;
13262         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13263             return s[++replaceIndex].buffer.join("");
13264         });
13265         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13266     },
13267
13268     apply : function(){
13269         return this.applyTemplate.apply(this, arguments);
13270     },
13271
13272     compile : function(){return this;}
13273 });
13274
13275 /**
13276  * Alias for fill().
13277  * @method
13278  */
13279 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13280  /**
13281  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13282  * var tpl = Roo.MasterTemplate.from('element-id');
13283  * @param {String/HTMLElement} el
13284  * @param {Object} config
13285  * @static
13286  */
13287 Roo.MasterTemplate.from = function(el, config){
13288     el = Roo.getDom(el);
13289     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13290 };/*
13291  * Based on:
13292  * Ext JS Library 1.1.1
13293  * Copyright(c) 2006-2007, Ext JS, LLC.
13294  *
13295  * Originally Released Under LGPL - original licence link has changed is not relivant.
13296  *
13297  * Fork - LGPL
13298  * <script type="text/javascript">
13299  */
13300
13301  
13302 /**
13303  * @class Roo.util.CSS
13304  * Utility class for manipulating CSS rules
13305  * @singleton
13306  */
13307 Roo.util.CSS = function(){
13308         var rules = null;
13309         var doc = document;
13310
13311     var camelRe = /(-[a-z])/gi;
13312     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13313
13314    return {
13315    /**
13316     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13317     * tag and appended to the HEAD of the document.
13318     * @param {String|Object} cssText The text containing the css rules
13319     * @param {String} id An id to add to the stylesheet for later removal
13320     * @return {StyleSheet}
13321     */
13322     createStyleSheet : function(cssText, id){
13323         var ss;
13324         var head = doc.getElementsByTagName("head")[0];
13325         var nrules = doc.createElement("style");
13326         nrules.setAttribute("type", "text/css");
13327         if(id){
13328             nrules.setAttribute("id", id);
13329         }
13330         if (typeof(cssText) != 'string') {
13331             // support object maps..
13332             // not sure if this a good idea.. 
13333             // perhaps it should be merged with the general css handling
13334             // and handle js style props.
13335             var cssTextNew = [];
13336             for(var n in cssText) {
13337                 var citems = [];
13338                 for(var k in cssText[n]) {
13339                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13340                 }
13341                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13342                 
13343             }
13344             cssText = cssTextNew.join("\n");
13345             
13346         }
13347        
13348        
13349        if(Roo.isIE){
13350            head.appendChild(nrules);
13351            ss = nrules.styleSheet;
13352            ss.cssText = cssText;
13353        }else{
13354            try{
13355                 nrules.appendChild(doc.createTextNode(cssText));
13356            }catch(e){
13357                nrules.cssText = cssText; 
13358            }
13359            head.appendChild(nrules);
13360            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13361        }
13362        this.cacheStyleSheet(ss);
13363        return ss;
13364    },
13365
13366    /**
13367     * Removes a style or link tag by id
13368     * @param {String} id The id of the tag
13369     */
13370    removeStyleSheet : function(id){
13371        var existing = doc.getElementById(id);
13372        if(existing){
13373            existing.parentNode.removeChild(existing);
13374        }
13375    },
13376
13377    /**
13378     * Dynamically swaps an existing stylesheet reference for a new one
13379     * @param {String} id The id of an existing link tag to remove
13380     * @param {String} url The href of the new stylesheet to include
13381     */
13382    swapStyleSheet : function(id, url){
13383        this.removeStyleSheet(id);
13384        var ss = doc.createElement("link");
13385        ss.setAttribute("rel", "stylesheet");
13386        ss.setAttribute("type", "text/css");
13387        ss.setAttribute("id", id);
13388        ss.setAttribute("href", url);
13389        doc.getElementsByTagName("head")[0].appendChild(ss);
13390    },
13391    
13392    /**
13393     * Refresh the rule cache if you have dynamically added stylesheets
13394     * @return {Object} An object (hash) of rules indexed by selector
13395     */
13396    refreshCache : function(){
13397        return this.getRules(true);
13398    },
13399
13400    // private
13401    cacheStyleSheet : function(stylesheet){
13402        if(!rules){
13403            rules = {};
13404        }
13405        try{// try catch for cross domain access issue
13406            var ssRules = stylesheet.cssRules || stylesheet.rules;
13407            for(var j = ssRules.length-1; j >= 0; --j){
13408                rules[ssRules[j].selectorText] = ssRules[j];
13409            }
13410        }catch(e){}
13411    },
13412    
13413    /**
13414     * Gets all css rules for the document
13415     * @param {Boolean} refreshCache true to refresh the internal cache
13416     * @return {Object} An object (hash) of rules indexed by selector
13417     */
13418    getRules : function(refreshCache){
13419                 if(rules == null || refreshCache){
13420                         rules = {};
13421                         var ds = doc.styleSheets;
13422                         for(var i =0, len = ds.length; i < len; i++){
13423                             try{
13424                         this.cacheStyleSheet(ds[i]);
13425                     }catch(e){} 
13426                 }
13427                 }
13428                 return rules;
13429         },
13430         
13431         /**
13432     * Gets an an individual CSS rule by selector(s)
13433     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13434     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13435     * @return {CSSRule} The CSS rule or null if one is not found
13436     */
13437    getRule : function(selector, refreshCache){
13438                 var rs = this.getRules(refreshCache);
13439                 if(!(selector instanceof Array)){
13440                     return rs[selector];
13441                 }
13442                 for(var i = 0; i < selector.length; i++){
13443                         if(rs[selector[i]]){
13444                                 return rs[selector[i]];
13445                         }
13446                 }
13447                 return null;
13448         },
13449         
13450         
13451         /**
13452     * Updates a rule property
13453     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13454     * @param {String} property The css property
13455     * @param {String} value The new value for the property
13456     * @return {Boolean} true If a rule was found and updated
13457     */
13458    updateRule : function(selector, property, value){
13459                 if(!(selector instanceof Array)){
13460                         var rule = this.getRule(selector);
13461                         if(rule){
13462                                 rule.style[property.replace(camelRe, camelFn)] = value;
13463                                 return true;
13464                         }
13465                 }else{
13466                         for(var i = 0; i < selector.length; i++){
13467                                 if(this.updateRule(selector[i], property, value)){
13468                                         return true;
13469                                 }
13470                         }
13471                 }
13472                 return false;
13473         }
13474    };   
13475 }();/*
13476  * Based on:
13477  * Ext JS Library 1.1.1
13478  * Copyright(c) 2006-2007, Ext JS, LLC.
13479  *
13480  * Originally Released Under LGPL - original licence link has changed is not relivant.
13481  *
13482  * Fork - LGPL
13483  * <script type="text/javascript">
13484  */
13485
13486  
13487
13488 /**
13489  * @class Roo.util.ClickRepeater
13490  * @extends Roo.util.Observable
13491  * 
13492  * A wrapper class which can be applied to any element. Fires a "click" event while the
13493  * mouse is pressed. The interval between firings may be specified in the config but
13494  * defaults to 10 milliseconds.
13495  * 
13496  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13497  * 
13498  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13499  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13500  * Similar to an autorepeat key delay.
13501  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13502  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13503  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13504  *           "interval" and "delay" are ignored. "immediate" is honored.
13505  * @cfg {Boolean} preventDefault True to prevent the default click event
13506  * @cfg {Boolean} stopDefault True to stop the default click event
13507  * 
13508  * @history
13509  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13510  *     2007-02-02 jvs Renamed to ClickRepeater
13511  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13512  *
13513  *  @constructor
13514  * @param {String/HTMLElement/Element} el The element to listen on
13515  * @param {Object} config
13516  **/
13517 Roo.util.ClickRepeater = function(el, config)
13518 {
13519     this.el = Roo.get(el);
13520     this.el.unselectable();
13521
13522     Roo.apply(this, config);
13523
13524     this.addEvents({
13525     /**
13526      * @event mousedown
13527      * Fires when the mouse button is depressed.
13528      * @param {Roo.util.ClickRepeater} this
13529      */
13530         "mousedown" : true,
13531     /**
13532      * @event click
13533      * Fires on a specified interval during the time the element is pressed.
13534      * @param {Roo.util.ClickRepeater} this
13535      */
13536         "click" : true,
13537     /**
13538      * @event mouseup
13539      * Fires when the mouse key is released.
13540      * @param {Roo.util.ClickRepeater} this
13541      */
13542         "mouseup" : true
13543     });
13544
13545     this.el.on("mousedown", this.handleMouseDown, this);
13546     if(this.preventDefault || this.stopDefault){
13547         this.el.on("click", function(e){
13548             if(this.preventDefault){
13549                 e.preventDefault();
13550             }
13551             if(this.stopDefault){
13552                 e.stopEvent();
13553             }
13554         }, this);
13555     }
13556
13557     // allow inline handler
13558     if(this.handler){
13559         this.on("click", this.handler,  this.scope || this);
13560     }
13561
13562     Roo.util.ClickRepeater.superclass.constructor.call(this);
13563 };
13564
13565 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13566     interval : 20,
13567     delay: 250,
13568     preventDefault : true,
13569     stopDefault : false,
13570     timer : 0,
13571
13572     // private
13573     handleMouseDown : function(){
13574         clearTimeout(this.timer);
13575         this.el.blur();
13576         if(this.pressClass){
13577             this.el.addClass(this.pressClass);
13578         }
13579         this.mousedownTime = new Date();
13580
13581         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13582         this.el.on("mouseout", this.handleMouseOut, this);
13583
13584         this.fireEvent("mousedown", this);
13585         this.fireEvent("click", this);
13586         
13587         this.timer = this.click.defer(this.delay || this.interval, this);
13588     },
13589
13590     // private
13591     click : function(){
13592         this.fireEvent("click", this);
13593         this.timer = this.click.defer(this.getInterval(), this);
13594     },
13595
13596     // private
13597     getInterval: function(){
13598         if(!this.accelerate){
13599             return this.interval;
13600         }
13601         var pressTime = this.mousedownTime.getElapsed();
13602         if(pressTime < 500){
13603             return 400;
13604         }else if(pressTime < 1700){
13605             return 320;
13606         }else if(pressTime < 2600){
13607             return 250;
13608         }else if(pressTime < 3500){
13609             return 180;
13610         }else if(pressTime < 4400){
13611             return 140;
13612         }else if(pressTime < 5300){
13613             return 80;
13614         }else if(pressTime < 6200){
13615             return 50;
13616         }else{
13617             return 10;
13618         }
13619     },
13620
13621     // private
13622     handleMouseOut : function(){
13623         clearTimeout(this.timer);
13624         if(this.pressClass){
13625             this.el.removeClass(this.pressClass);
13626         }
13627         this.el.on("mouseover", this.handleMouseReturn, this);
13628     },
13629
13630     // private
13631     handleMouseReturn : function(){
13632         this.el.un("mouseover", this.handleMouseReturn);
13633         if(this.pressClass){
13634             this.el.addClass(this.pressClass);
13635         }
13636         this.click();
13637     },
13638
13639     // private
13640     handleMouseUp : function(){
13641         clearTimeout(this.timer);
13642         this.el.un("mouseover", this.handleMouseReturn);
13643         this.el.un("mouseout", this.handleMouseOut);
13644         Roo.get(document).un("mouseup", this.handleMouseUp);
13645         this.el.removeClass(this.pressClass);
13646         this.fireEvent("mouseup", this);
13647     }
13648 });/*
13649  * Based on:
13650  * Ext JS Library 1.1.1
13651  * Copyright(c) 2006-2007, Ext JS, LLC.
13652  *
13653  * Originally Released Under LGPL - original licence link has changed is not relivant.
13654  *
13655  * Fork - LGPL
13656  * <script type="text/javascript">
13657  */
13658
13659  
13660 /**
13661  * @class Roo.KeyNav
13662  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13663  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13664  * way to implement custom navigation schemes for any UI component.</p>
13665  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13666  * pageUp, pageDown, del, home, end.  Usage:</p>
13667  <pre><code>
13668 var nav = new Roo.KeyNav("my-element", {
13669     "left" : function(e){
13670         this.moveLeft(e.ctrlKey);
13671     },
13672     "right" : function(e){
13673         this.moveRight(e.ctrlKey);
13674     },
13675     "enter" : function(e){
13676         this.save();
13677     },
13678     scope : this
13679 });
13680 </code></pre>
13681  * @constructor
13682  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13683  * @param {Object} config The config
13684  */
13685 Roo.KeyNav = function(el, config){
13686     this.el = Roo.get(el);
13687     Roo.apply(this, config);
13688     if(!this.disabled){
13689         this.disabled = true;
13690         this.enable();
13691     }
13692 };
13693
13694 Roo.KeyNav.prototype = {
13695     /**
13696      * @cfg {Boolean} disabled
13697      * True to disable this KeyNav instance (defaults to false)
13698      */
13699     disabled : false,
13700     /**
13701      * @cfg {String} defaultEventAction
13702      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13703      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13704      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13705      */
13706     defaultEventAction: "stopEvent",
13707     /**
13708      * @cfg {Boolean} forceKeyDown
13709      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13710      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13711      * handle keydown instead of keypress.
13712      */
13713     forceKeyDown : false,
13714
13715     // private
13716     prepareEvent : function(e){
13717         var k = e.getKey();
13718         var h = this.keyToHandler[k];
13719         //if(h && this[h]){
13720         //    e.stopPropagation();
13721         //}
13722         if(Roo.isSafari && h && k >= 37 && k <= 40){
13723             e.stopEvent();
13724         }
13725     },
13726
13727     // private
13728     relay : function(e){
13729         var k = e.getKey();
13730         var h = this.keyToHandler[k];
13731         if(h && this[h]){
13732             if(this.doRelay(e, this[h], h) !== true){
13733                 e[this.defaultEventAction]();
13734             }
13735         }
13736     },
13737
13738     // private
13739     doRelay : function(e, h, hname){
13740         return h.call(this.scope || this, e);
13741     },
13742
13743     // possible handlers
13744     enter : false,
13745     left : false,
13746     right : false,
13747     up : false,
13748     down : false,
13749     tab : false,
13750     esc : false,
13751     pageUp : false,
13752     pageDown : false,
13753     del : false,
13754     home : false,
13755     end : false,
13756
13757     // quick lookup hash
13758     keyToHandler : {
13759         37 : "left",
13760         39 : "right",
13761         38 : "up",
13762         40 : "down",
13763         33 : "pageUp",
13764         34 : "pageDown",
13765         46 : "del",
13766         36 : "home",
13767         35 : "end",
13768         13 : "enter",
13769         27 : "esc",
13770         9  : "tab"
13771     },
13772
13773         /**
13774          * Enable this KeyNav
13775          */
13776         enable: function(){
13777                 if(this.disabled){
13778             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13779             // the EventObject will normalize Safari automatically
13780             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13781                 this.el.on("keydown", this.relay,  this);
13782             }else{
13783                 this.el.on("keydown", this.prepareEvent,  this);
13784                 this.el.on("keypress", this.relay,  this);
13785             }
13786                     this.disabled = false;
13787                 }
13788         },
13789
13790         /**
13791          * Disable this KeyNav
13792          */
13793         disable: function(){
13794                 if(!this.disabled){
13795                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13796                 this.el.un("keydown", this.relay);
13797             }else{
13798                 this.el.un("keydown", this.prepareEvent);
13799                 this.el.un("keypress", this.relay);
13800             }
13801                     this.disabled = true;
13802                 }
13803         }
13804 };/*
13805  * Based on:
13806  * Ext JS Library 1.1.1
13807  * Copyright(c) 2006-2007, Ext JS, LLC.
13808  *
13809  * Originally Released Under LGPL - original licence link has changed is not relivant.
13810  *
13811  * Fork - LGPL
13812  * <script type="text/javascript">
13813  */
13814
13815  
13816 /**
13817  * @class Roo.KeyMap
13818  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13819  * The constructor accepts the same config object as defined by {@link #addBinding}.
13820  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13821  * combination it will call the function with this signature (if the match is a multi-key
13822  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13823  * A KeyMap can also handle a string representation of keys.<br />
13824  * Usage:
13825  <pre><code>
13826 // map one key by key code
13827 var map = new Roo.KeyMap("my-element", {
13828     key: 13, // or Roo.EventObject.ENTER
13829     fn: myHandler,
13830     scope: myObject
13831 });
13832
13833 // map multiple keys to one action by string
13834 var map = new Roo.KeyMap("my-element", {
13835     key: "a\r\n\t",
13836     fn: myHandler,
13837     scope: myObject
13838 });
13839
13840 // map multiple keys to multiple actions by strings and array of codes
13841 var map = new Roo.KeyMap("my-element", [
13842     {
13843         key: [10,13],
13844         fn: function(){ alert("Return was pressed"); }
13845     }, {
13846         key: "abc",
13847         fn: function(){ alert('a, b or c was pressed'); }
13848     }, {
13849         key: "\t",
13850         ctrl:true,
13851         shift:true,
13852         fn: function(){ alert('Control + shift + tab was pressed.'); }
13853     }
13854 ]);
13855 </code></pre>
13856  * <b>Note: A KeyMap starts enabled</b>
13857  * @constructor
13858  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13859  * @param {Object} config The config (see {@link #addBinding})
13860  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13861  */
13862 Roo.KeyMap = function(el, config, eventName){
13863     this.el  = Roo.get(el);
13864     this.eventName = eventName || "keydown";
13865     this.bindings = [];
13866     if(config){
13867         this.addBinding(config);
13868     }
13869     this.enable();
13870 };
13871
13872 Roo.KeyMap.prototype = {
13873     /**
13874      * True to stop the event from bubbling and prevent the default browser action if the
13875      * key was handled by the KeyMap (defaults to false)
13876      * @type Boolean
13877      */
13878     stopEvent : false,
13879
13880     /**
13881      * Add a new binding to this KeyMap. The following config object properties are supported:
13882      * <pre>
13883 Property    Type             Description
13884 ----------  ---------------  ----------------------------------------------------------------------
13885 key         String/Array     A single keycode or an array of keycodes to handle
13886 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13887 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13888 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13889 fn          Function         The function to call when KeyMap finds the expected key combination
13890 scope       Object           The scope of the callback function
13891 </pre>
13892      *
13893      * Usage:
13894      * <pre><code>
13895 // Create a KeyMap
13896 var map = new Roo.KeyMap(document, {
13897     key: Roo.EventObject.ENTER,
13898     fn: handleKey,
13899     scope: this
13900 });
13901
13902 //Add a new binding to the existing KeyMap later
13903 map.addBinding({
13904     key: 'abc',
13905     shift: true,
13906     fn: handleKey,
13907     scope: this
13908 });
13909 </code></pre>
13910      * @param {Object/Array} config A single KeyMap config or an array of configs
13911      */
13912         addBinding : function(config){
13913         if(config instanceof Array){
13914             for(var i = 0, len = config.length; i < len; i++){
13915                 this.addBinding(config[i]);
13916             }
13917             return;
13918         }
13919         var keyCode = config.key,
13920             shift = config.shift, 
13921             ctrl = config.ctrl, 
13922             alt = config.alt,
13923             fn = config.fn,
13924             scope = config.scope;
13925         if(typeof keyCode == "string"){
13926             var ks = [];
13927             var keyString = keyCode.toUpperCase();
13928             for(var j = 0, len = keyString.length; j < len; j++){
13929                 ks.push(keyString.charCodeAt(j));
13930             }
13931             keyCode = ks;
13932         }
13933         var keyArray = keyCode instanceof Array;
13934         var handler = function(e){
13935             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13936                 var k = e.getKey();
13937                 if(keyArray){
13938                     for(var i = 0, len = keyCode.length; i < len; i++){
13939                         if(keyCode[i] == k){
13940                           if(this.stopEvent){
13941                               e.stopEvent();
13942                           }
13943                           fn.call(scope || window, k, e);
13944                           return;
13945                         }
13946                     }
13947                 }else{
13948                     if(k == keyCode){
13949                         if(this.stopEvent){
13950                            e.stopEvent();
13951                         }
13952                         fn.call(scope || window, k, e);
13953                     }
13954                 }
13955             }
13956         };
13957         this.bindings.push(handler);  
13958         },
13959
13960     /**
13961      * Shorthand for adding a single key listener
13962      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13963      * following options:
13964      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13965      * @param {Function} fn The function to call
13966      * @param {Object} scope (optional) The scope of the function
13967      */
13968     on : function(key, fn, scope){
13969         var keyCode, shift, ctrl, alt;
13970         if(typeof key == "object" && !(key instanceof Array)){
13971             keyCode = key.key;
13972             shift = key.shift;
13973             ctrl = key.ctrl;
13974             alt = key.alt;
13975         }else{
13976             keyCode = key;
13977         }
13978         this.addBinding({
13979             key: keyCode,
13980             shift: shift,
13981             ctrl: ctrl,
13982             alt: alt,
13983             fn: fn,
13984             scope: scope
13985         })
13986     },
13987
13988     // private
13989     handleKeyDown : function(e){
13990             if(this.enabled){ //just in case
13991             var b = this.bindings;
13992             for(var i = 0, len = b.length; i < len; i++){
13993                 b[i].call(this, e);
13994             }
13995             }
13996         },
13997         
13998         /**
13999          * Returns true if this KeyMap is enabled
14000          * @return {Boolean} 
14001          */
14002         isEnabled : function(){
14003             return this.enabled;  
14004         },
14005         
14006         /**
14007          * Enables this KeyMap
14008          */
14009         enable: function(){
14010                 if(!this.enabled){
14011                     this.el.on(this.eventName, this.handleKeyDown, this);
14012                     this.enabled = true;
14013                 }
14014         },
14015
14016         /**
14017          * Disable this KeyMap
14018          */
14019         disable: function(){
14020                 if(this.enabled){
14021                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14022                     this.enabled = false;
14023                 }
14024         }
14025 };/*
14026  * Based on:
14027  * Ext JS Library 1.1.1
14028  * Copyright(c) 2006-2007, Ext JS, LLC.
14029  *
14030  * Originally Released Under LGPL - original licence link has changed is not relivant.
14031  *
14032  * Fork - LGPL
14033  * <script type="text/javascript">
14034  */
14035
14036  
14037 /**
14038  * @class Roo.util.TextMetrics
14039  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14040  * wide, in pixels, a given block of text will be.
14041  * @singleton
14042  */
14043 Roo.util.TextMetrics = function(){
14044     var shared;
14045     return {
14046         /**
14047          * Measures the size of the specified text
14048          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14049          * that can affect the size of the rendered text
14050          * @param {String} text The text to measure
14051          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14052          * in order to accurately measure the text height
14053          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14054          */
14055         measure : function(el, text, fixedWidth){
14056             if(!shared){
14057                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14058             }
14059             shared.bind(el);
14060             shared.setFixedWidth(fixedWidth || 'auto');
14061             return shared.getSize(text);
14062         },
14063
14064         /**
14065          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14066          * the overhead of multiple calls to initialize the style properties on each measurement.
14067          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14068          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14069          * in order to accurately measure the text height
14070          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14071          */
14072         createInstance : function(el, fixedWidth){
14073             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14074         }
14075     };
14076 }();
14077
14078  
14079
14080 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14081     var ml = new Roo.Element(document.createElement('div'));
14082     document.body.appendChild(ml.dom);
14083     ml.position('absolute');
14084     ml.setLeftTop(-1000, -1000);
14085     ml.hide();
14086
14087     if(fixedWidth){
14088         ml.setWidth(fixedWidth);
14089     }
14090      
14091     var instance = {
14092         /**
14093          * Returns the size of the specified text based on the internal element's style and width properties
14094          * @memberOf Roo.util.TextMetrics.Instance#
14095          * @param {String} text The text to measure
14096          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14097          */
14098         getSize : function(text){
14099             ml.update(text);
14100             var s = ml.getSize();
14101             ml.update('');
14102             return s;
14103         },
14104
14105         /**
14106          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14107          * that can affect the size of the rendered text
14108          * @memberOf Roo.util.TextMetrics.Instance#
14109          * @param {String/HTMLElement} el The element, dom node or id
14110          */
14111         bind : function(el){
14112             ml.setStyle(
14113                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14114             );
14115         },
14116
14117         /**
14118          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14119          * to set a fixed width in order to accurately measure the text height.
14120          * @memberOf Roo.util.TextMetrics.Instance#
14121          * @param {Number} width The width to set on the element
14122          */
14123         setFixedWidth : function(width){
14124             ml.setWidth(width);
14125         },
14126
14127         /**
14128          * Returns the measured width of the specified text
14129          * @memberOf Roo.util.TextMetrics.Instance#
14130          * @param {String} text The text to measure
14131          * @return {Number} width The width in pixels
14132          */
14133         getWidth : function(text){
14134             ml.dom.style.width = 'auto';
14135             return this.getSize(text).width;
14136         },
14137
14138         /**
14139          * Returns the measured height of the specified text.  For multiline text, be sure to call
14140          * {@link #setFixedWidth} if necessary.
14141          * @memberOf Roo.util.TextMetrics.Instance#
14142          * @param {String} text The text to measure
14143          * @return {Number} height The height in pixels
14144          */
14145         getHeight : function(text){
14146             return this.getSize(text).height;
14147         }
14148     };
14149
14150     instance.bind(bindTo);
14151
14152     return instance;
14153 };
14154
14155 // backwards compat
14156 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14157  * Based on:
14158  * Ext JS Library 1.1.1
14159  * Copyright(c) 2006-2007, Ext JS, LLC.
14160  *
14161  * Originally Released Under LGPL - original licence link has changed is not relivant.
14162  *
14163  * Fork - LGPL
14164  * <script type="text/javascript">
14165  */
14166
14167 /**
14168  * @class Roo.state.Provider
14169  * Abstract base class for state provider implementations. This class provides methods
14170  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14171  * Provider interface.
14172  */
14173 Roo.state.Provider = function(){
14174     /**
14175      * @event statechange
14176      * Fires when a state change occurs.
14177      * @param {Provider} this This state provider
14178      * @param {String} key The state key which was changed
14179      * @param {String} value The encoded value for the state
14180      */
14181     this.addEvents({
14182         "statechange": true
14183     });
14184     this.state = {};
14185     Roo.state.Provider.superclass.constructor.call(this);
14186 };
14187 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14188     /**
14189      * Returns the current value for a key
14190      * @param {String} name The key name
14191      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14192      * @return {Mixed} The state data
14193      */
14194     get : function(name, defaultValue){
14195         return typeof this.state[name] == "undefined" ?
14196             defaultValue : this.state[name];
14197     },
14198     
14199     /**
14200      * Clears a value from the state
14201      * @param {String} name The key name
14202      */
14203     clear : function(name){
14204         delete this.state[name];
14205         this.fireEvent("statechange", this, name, null);
14206     },
14207     
14208     /**
14209      * Sets the value for a key
14210      * @param {String} name The key name
14211      * @param {Mixed} value The value to set
14212      */
14213     set : function(name, value){
14214         this.state[name] = value;
14215         this.fireEvent("statechange", this, name, value);
14216     },
14217     
14218     /**
14219      * Decodes a string previously encoded with {@link #encodeValue}.
14220      * @param {String} value The value to decode
14221      * @return {Mixed} The decoded value
14222      */
14223     decodeValue : function(cookie){
14224         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14225         var matches = re.exec(unescape(cookie));
14226         if(!matches || !matches[1]) return; // non state cookie
14227         var type = matches[1];
14228         var v = matches[2];
14229         switch(type){
14230             case "n":
14231                 return parseFloat(v);
14232             case "d":
14233                 return new Date(Date.parse(v));
14234             case "b":
14235                 return (v == "1");
14236             case "a":
14237                 var all = [];
14238                 var values = v.split("^");
14239                 for(var i = 0, len = values.length; i < len; i++){
14240                     all.push(this.decodeValue(values[i]));
14241                 }
14242                 return all;
14243            case "o":
14244                 var all = {};
14245                 var values = v.split("^");
14246                 for(var i = 0, len = values.length; i < len; i++){
14247                     var kv = values[i].split("=");
14248                     all[kv[0]] = this.decodeValue(kv[1]);
14249                 }
14250                 return all;
14251            default:
14252                 return v;
14253         }
14254     },
14255     
14256     /**
14257      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14258      * @param {Mixed} value The value to encode
14259      * @return {String} The encoded value
14260      */
14261     encodeValue : function(v){
14262         var enc;
14263         if(typeof v == "number"){
14264             enc = "n:" + v;
14265         }else if(typeof v == "boolean"){
14266             enc = "b:" + (v ? "1" : "0");
14267         }else if(v instanceof Date){
14268             enc = "d:" + v.toGMTString();
14269         }else if(v instanceof Array){
14270             var flat = "";
14271             for(var i = 0, len = v.length; i < len; i++){
14272                 flat += this.encodeValue(v[i]);
14273                 if(i != len-1) flat += "^";
14274             }
14275             enc = "a:" + flat;
14276         }else if(typeof v == "object"){
14277             var flat = "";
14278             for(var key in v){
14279                 if(typeof v[key] != "function"){
14280                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14281                 }
14282             }
14283             enc = "o:" + flat.substring(0, flat.length-1);
14284         }else{
14285             enc = "s:" + v;
14286         }
14287         return escape(enc);        
14288     }
14289 });
14290
14291 /*
14292  * Based on:
14293  * Ext JS Library 1.1.1
14294  * Copyright(c) 2006-2007, Ext JS, LLC.
14295  *
14296  * Originally Released Under LGPL - original licence link has changed is not relivant.
14297  *
14298  * Fork - LGPL
14299  * <script type="text/javascript">
14300  */
14301 /**
14302  * @class Roo.state.Manager
14303  * This is the global state manager. By default all components that are "state aware" check this class
14304  * for state information if you don't pass them a custom state provider. In order for this class
14305  * to be useful, it must be initialized with a provider when your application initializes.
14306  <pre><code>
14307 // in your initialization function
14308 init : function(){
14309    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14310    ...
14311    // supposed you have a {@link Roo.BorderLayout}
14312    var layout = new Roo.BorderLayout(...);
14313    layout.restoreState();
14314    // or a {Roo.BasicDialog}
14315    var dialog = new Roo.BasicDialog(...);
14316    dialog.restoreState();
14317  </code></pre>
14318  * @singleton
14319  */
14320 Roo.state.Manager = function(){
14321     var provider = new Roo.state.Provider();
14322     
14323     return {
14324         /**
14325          * Configures the default state provider for your application
14326          * @param {Provider} stateProvider The state provider to set
14327          */
14328         setProvider : function(stateProvider){
14329             provider = stateProvider;
14330         },
14331         
14332         /**
14333          * Returns the current value for a key
14334          * @param {String} name The key name
14335          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14336          * @return {Mixed} The state data
14337          */
14338         get : function(key, defaultValue){
14339             return provider.get(key, defaultValue);
14340         },
14341         
14342         /**
14343          * Sets the value for a key
14344          * @param {String} name The key name
14345          * @param {Mixed} value The state data
14346          */
14347          set : function(key, value){
14348             provider.set(key, value);
14349         },
14350         
14351         /**
14352          * Clears a value from the state
14353          * @param {String} name The key name
14354          */
14355         clear : function(key){
14356             provider.clear(key);
14357         },
14358         
14359         /**
14360          * Gets the currently configured state provider
14361          * @return {Provider} The state provider
14362          */
14363         getProvider : function(){
14364             return provider;
14365         }
14366     };
14367 }();
14368 /*
14369  * Based on:
14370  * Ext JS Library 1.1.1
14371  * Copyright(c) 2006-2007, Ext JS, LLC.
14372  *
14373  * Originally Released Under LGPL - original licence link has changed is not relivant.
14374  *
14375  * Fork - LGPL
14376  * <script type="text/javascript">
14377  */
14378 /**
14379  * @class Roo.state.CookieProvider
14380  * @extends Roo.state.Provider
14381  * The default Provider implementation which saves state via cookies.
14382  * <br />Usage:
14383  <pre><code>
14384    var cp = new Roo.state.CookieProvider({
14385        path: "/cgi-bin/",
14386        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14387        domain: "roojs.com"
14388    })
14389    Roo.state.Manager.setProvider(cp);
14390  </code></pre>
14391  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14392  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14393  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14394  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14395  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14396  * domain the page is running on including the 'www' like 'www.roojs.com')
14397  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14398  * @constructor
14399  * Create a new CookieProvider
14400  * @param {Object} config The configuration object
14401  */
14402 Roo.state.CookieProvider = function(config){
14403     Roo.state.CookieProvider.superclass.constructor.call(this);
14404     this.path = "/";
14405     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14406     this.domain = null;
14407     this.secure = false;
14408     Roo.apply(this, config);
14409     this.state = this.readCookies();
14410 };
14411
14412 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14413     // private
14414     set : function(name, value){
14415         if(typeof value == "undefined" || value === null){
14416             this.clear(name);
14417             return;
14418         }
14419         this.setCookie(name, value);
14420         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14421     },
14422
14423     // private
14424     clear : function(name){
14425         this.clearCookie(name);
14426         Roo.state.CookieProvider.superclass.clear.call(this, name);
14427     },
14428
14429     // private
14430     readCookies : function(){
14431         var cookies = {};
14432         var c = document.cookie + ";";
14433         var re = /\s?(.*?)=(.*?);/g;
14434         var matches;
14435         while((matches = re.exec(c)) != null){
14436             var name = matches[1];
14437             var value = matches[2];
14438             if(name && name.substring(0,3) == "ys-"){
14439                 cookies[name.substr(3)] = this.decodeValue(value);
14440             }
14441         }
14442         return cookies;
14443     },
14444
14445     // private
14446     setCookie : function(name, value){
14447         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14448            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14449            ((this.path == null) ? "" : ("; path=" + this.path)) +
14450            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14451            ((this.secure == true) ? "; secure" : "");
14452     },
14453
14454     // private
14455     clearCookie : function(name){
14456         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14457            ((this.path == null) ? "" : ("; path=" + this.path)) +
14458            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14459            ((this.secure == true) ? "; secure" : "");
14460     }
14461 });