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