Roo/dd/DragDrop.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64         isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123         
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618         /** @type Boolean */
619         isTouch : isTouch,
620
621         /**
622          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623          * you may want to set this to true.
624          * @type Boolean
625          */
626         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
627         
628         
629                 
630         /**
631          * Selects a single element as a Roo Element
632          * This is about as close as you can get to jQuery's $('do crazy stuff')
633          * @param {String} selector The selector/xpath query
634          * @param {Node} root (optional) The start of the query (defaults to document).
635          * @return {Roo.Element}
636          */
637         selectNode : function(selector, root) 
638         {
639             var node = Roo.DomQuery.selectNode(selector,root);
640             return node ? Roo.get(node) : new Roo.Element(false);
641         }
642         
643     });
644
645
646 })();
647
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 /*
651  * Based on:
652  * Ext JS Library 1.1.1
653  * Copyright(c) 2006-2007, Ext JS, LLC.
654  *
655  * Originally Released Under LGPL - original licence link has changed is not relivant.
656  *
657  * Fork - LGPL
658  * <script type="text/javascript">
659  */
660
661 (function() {    
662     // wrappedn so fnCleanup is not in global scope...
663     if(Roo.isIE) {
664         function fnCleanUp() {
665             var p = Function.prototype;
666             delete p.createSequence;
667             delete p.defer;
668             delete p.createDelegate;
669             delete p.createCallback;
670             delete p.createInterceptor;
671
672             window.detachEvent("onunload", fnCleanUp);
673         }
674         window.attachEvent("onunload", fnCleanUp);
675     }
676 })();
677
678
679 /**
680  * @class Function
681  * These functions are available on every Function object (any JavaScript function).
682  */
683 Roo.apply(Function.prototype, {
684      /**
685      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687      * Will create a function that is bound to those 2 args.
688      * @return {Function} The new function
689     */
690     createCallback : function(/*args...*/){
691         // make args available, in function below
692         var args = arguments;
693         var method = this;
694         return function() {
695             return method.apply(window, args);
696         };
697     },
698
699     /**
700      * Creates a delegate (callback) that sets the scope to obj.
701      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702      * Will create a function that is automatically scoped to this.
703      * @param {Object} obj (optional) The object for which the scope is set
704      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706      *                                             if a number the args are inserted at the specified position
707      * @return {Function} The new function
708      */
709     createDelegate : function(obj, args, appendArgs){
710         var method = this;
711         return function() {
712             var callArgs = args || arguments;
713             if(appendArgs === true){
714                 callArgs = Array.prototype.slice.call(arguments, 0);
715                 callArgs = callArgs.concat(args);
716             }else if(typeof appendArgs == "number"){
717                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
720             }
721             return method.apply(obj || window, callArgs);
722         };
723     },
724
725     /**
726      * Calls this function after the number of millseconds specified.
727      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728      * @param {Object} obj (optional) The object for which the scope is set
729      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731      *                                             if a number the args are inserted at the specified position
732      * @return {Number} The timeout id that can be used with clearTimeout
733      */
734     defer : function(millis, obj, args, appendArgs){
735         var fn = this.createDelegate(obj, args, appendArgs);
736         if(millis){
737             return setTimeout(fn, millis);
738         }
739         fn();
740         return 0;
741     },
742     /**
743      * Create a combined function call sequence of the original function + the passed function.
744      * The resulting function returns the results of the original function.
745      * The passed fcn is called with the parameters of the original function
746      * @param {Function} fcn The function to sequence
747      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748      * @return {Function} The new function
749      */
750     createSequence : function(fcn, scope){
751         if(typeof fcn != "function"){
752             return this;
753         }
754         var method = this;
755         return function() {
756             var retval = method.apply(this || window, arguments);
757             fcn.apply(scope || this || window, arguments);
758             return retval;
759         };
760     },
761
762     /**
763      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function.
766      * @addon
767      * @param {Function} fcn The function to call before the original
768      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769      * @return {Function} The new function
770      */
771     createInterceptor : function(fcn, scope){
772         if(typeof fcn != "function"){
773             return this;
774         }
775         var method = this;
776         return function() {
777             fcn.target = this;
778             fcn.method = method;
779             if(fcn.apply(scope || this || window, arguments) === false){
780                 return;
781             }
782             return method.apply(this || window, arguments);
783         };
784     }
785 });
786 /*
787  * Based on:
788  * Ext JS Library 1.1.1
789  * Copyright(c) 2006-2007, Ext JS, LLC.
790  *
791  * Originally Released Under LGPL - original licence link has changed is not relivant.
792  *
793  * Fork - LGPL
794  * <script type="text/javascript">
795  */
796
797 Roo.applyIf(String, {
798     
799     /** @scope String */
800     
801     /**
802      * Escapes the passed string for ' and \
803      * @param {String} string The string to escape
804      * @return {String} The escaped string
805      * @static
806      */
807     escape : function(string) {
808         return string.replace(/('|\\)/g, "\\$1");
809     },
810
811     /**
812      * Pads the left side of a string with a specified character.  This is especially useful
813      * for normalizing number and date strings.  Example usage:
814      * <pre><code>
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
817 </code></pre>
818      * @param {String} string The original string
819      * @param {Number} size The total length of the output string
820      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821      * @return {String} The padded string
822      * @static
823      */
824     leftPad : function (val, size, ch) {
825         var result = new String(val);
826         if(ch === null || ch === undefined || ch === '') {
827             ch = " ";
828         }
829         while (result.length < size) {
830             result = ch + result;
831         }
832         return result;
833     },
834
835     /**
836      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
837      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
838      * <pre><code>
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
842 </code></pre>
843      * @param {String} string The tokenized string to be formatted
844      * @param {String} value1 The value to replace token {0}
845      * @param {String} value2 Etc...
846      * @return {String} The formatted string
847      * @static
848      */
849     format : function(format){
850         var args = Array.prototype.slice.call(arguments, 1);
851         return format.replace(/\{(\d+)\}/g, function(m, i){
852             return Roo.util.Format.htmlEncode(args[i]);
853         });
854     }
855 });
856
857 /**
858  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
859  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
860  * they are already different, the first value passed in is returned.  Note that this method returns the new value
861  * but does not change the current string.
862  * <pre><code>
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
865
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
868 </code></pre>
869  * @param {String} value The value to compare to the current string
870  * @param {String} other The new value to use if the string already equals the first value passed in
871  * @return {String} The new value
872  */
873  
874 String.prototype.toggle = function(value, other){
875     return this == value ? other : value;
876 };/*
877  * Based on:
878  * Ext JS Library 1.1.1
879  * Copyright(c) 2006-2007, Ext JS, LLC.
880  *
881  * Originally Released Under LGPL - original licence link has changed is not relivant.
882  *
883  * Fork - LGPL
884  * <script type="text/javascript">
885  */
886
887  /**
888  * @class Number
889  */
890 Roo.applyIf(Number.prototype, {
891     /**
892      * Checks whether or not the current number is within a desired range.  If the number is already within the
893      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894      * exceeded.  Note that this method returns the constrained value but does not change the current number.
895      * @param {Number} min The minimum number in the range
896      * @param {Number} max The maximum number in the range
897      * @return {Number} The constrained value if outside the range, otherwise the current value
898      */
899     constrain : function(min, max){
900         return Math.min(Math.max(this, min), max);
901     }
902 });/*
903  * Based on:
904  * Ext JS Library 1.1.1
905  * Copyright(c) 2006-2007, Ext JS, LLC.
906  *
907  * Originally Released Under LGPL - original licence link has changed is not relivant.
908  *
909  * Fork - LGPL
910  * <script type="text/javascript">
911  */
912  /**
913  * @class Array
914  */
915 Roo.applyIf(Array.prototype, {
916     /**
917      * Checks whether or not the specified object exists in the array.
918      * @param {Object} o The object to check for
919      * @return {Number} The index of o in the array (or -1 if it is not found)
920      */
921     indexOf : function(o){
922        for (var i = 0, len = this.length; i < len; i++){
923               if(this[i] == o) return i;
924        }
925            return -1;
926     },
927
928     /**
929      * Removes the specified object from the array.  If the object is not found nothing happens.
930      * @param {Object} o The object to remove
931      */
932     remove : function(o){
933        var index = this.indexOf(o);
934        if(index != -1){
935            this.splice(index, 1);
936        }
937     },
938     /**
939      * Map (JS 1.6 compatibility)
940      * @param {Function} function  to call
941      */
942     map : function(fun )
943     {
944         var len = this.length >>> 0;
945         if (typeof fun != "function")
946             throw new TypeError();
947
948         var res = new Array(len);
949         var thisp = arguments[1];
950         for (var i = 0; i < len; i++)
951         {
952             if (i in this)
953                 res[i] = fun.call(thisp, this[i], i, this);
954         }
955
956         return res;
957     }
958     
959 });
960
961
962  /*
963  * Based on:
964  * Ext JS Library 1.1.1
965  * Copyright(c) 2006-2007, Ext JS, LLC.
966  *
967  * Originally Released Under LGPL - original licence link has changed is not relivant.
968  *
969  * Fork - LGPL
970  * <script type="text/javascript">
971  */
972
973 /**
974  * @class Date
975  *
976  * The date parsing and format syntax is a subset of
977  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978  * supported will provide results equivalent to their PHP versions.
979  *
980  * Following is the list of all currently supported formats:
981  *<pre>
982 Sample date:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
984
985 Format  Output      Description
986 ------  ----------  --------------------------------------------------------------
987   d      10         Day of the month, 2 digits with leading zeros
988   D      Wed        A textual representation of a day, three letters
989   j      10         Day of the month without leading zeros
990   l      Wednesday  A full textual representation of the day of the week
991   S      th         English ordinal day of month suffix, 2 chars (use with j)
992   w      3          Numeric representation of the day of the week
993   z      9          The julian date, or day of the year (0-365)
994   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995   F      January    A full textual representation of the month
996   m      01         Numeric representation of a month, with leading zeros
997   M      Jan        Month name abbreviation, three letters
998   n      1          Numeric representation of a month, without leading zeros
999   t      31         Number of days in the given month
1000   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1001   Y      2007       A full numeric representation of a year, 4 digits
1002   y      07         A two digit representation of a year
1003   a      pm         Lowercase Ante meridiem and Post meridiem
1004   A      PM         Uppercase Ante meridiem and Post meridiem
1005   g      3          12-hour format of an hour without leading zeros
1006   G      15         24-hour format of an hour without leading zeros
1007   h      03         12-hour format of an hour with leading zeros
1008   H      15         24-hour format of an hour with leading zeros
1009   i      05         Minutes with leading zeros
1010   s      01         Seconds, with leading zeros
1011   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1013   T      CST        Timezone setting of the machine running the code
1014   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1015 </pre>
1016  *
1017  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1018  * <pre><code>
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d'));                         //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1023  </code></pre>
1024  *
1025  * Here are some standard date/time patterns that you might find helpful.  They
1026  * are not part of the source of Date.js, but to use them you can simply copy this
1027  * block of code into any script that is included after Date.js and they will also become
1028  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1029  * <pre><code>
1030 Date.patterns = {
1031     ISO8601Long:"Y-m-d H:i:s",
1032     ISO8601Short:"Y-m-d",
1033     ShortDate: "n/j/Y",
1034     LongDate: "l, F d, Y",
1035     FullDateTime: "l, F d, Y g:i:s A",
1036     MonthDay: "F d",
1037     ShortTime: "g:i A",
1038     LongTime: "g:i:s A",
1039     SortableDateTime: "Y-m-d\\TH:i:s",
1040     UniversalSortableDateTime: "Y-m-d H:i:sO",
1041     YearMonth: "F, Y"
1042 };
1043 </code></pre>
1044  *
1045  * Example usage:
1046  * <pre><code>
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1049  </code></pre>
1050  */
1051
1052 /*
1053  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054  * They generate precompiled functions from date formats instead of parsing and
1055  * processing the pattern every time you format a date.  These functions are available
1056  * on every Date object (any javascript function).
1057  *
1058  * The original article and download are here:
1059  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1060  *
1061  */
1062  
1063  
1064  // was in core
1065 /**
1066  Returns the number of milliseconds between this date and date
1067  @param {Date} date (optional) Defaults to now
1068  @return {Number} The diff in milliseconds
1069  @member Date getElapsed
1070  */
1071 Date.prototype.getElapsed = function(date) {
1072         return Math.abs((date || new Date()).getTime()-this.getTime());
1073 };
1074 // was in date file..
1075
1076
1077 // private
1078 Date.parseFunctions = {count:0};
1079 // private
1080 Date.parseRegexes = [];
1081 // private
1082 Date.formatFunctions = {count:0};
1083
1084 // private
1085 Date.prototype.dateFormat = function(format) {
1086     if (Date.formatFunctions[format] == null) {
1087         Date.createNewFormat(format);
1088     }
1089     var func = Date.formatFunctions[format];
1090     return this[func]();
1091 };
1092
1093
1094 /**
1095  * Formats a date given the supplied format string
1096  * @param {String} format The format string
1097  * @return {String} The formatted date
1098  * @method
1099  */
1100 Date.prototype.format = Date.prototype.dateFormat;
1101
1102 // private
1103 Date.createNewFormat = function(format) {
1104     var funcName = "format" + Date.formatFunctions.count++;
1105     Date.formatFunctions[format] = funcName;
1106     var code = "Date.prototype." + funcName + " = function(){return ";
1107     var special = false;
1108     var ch = '';
1109     for (var i = 0; i < format.length; ++i) {
1110         ch = format.charAt(i);
1111         if (!special && ch == "\\") {
1112             special = true;
1113         }
1114         else if (special) {
1115             special = false;
1116             code += "'" + String.escape(ch) + "' + ";
1117         }
1118         else {
1119             code += Date.getFormatCode(ch);
1120         }
1121     }
1122     /** eval:var:zzzzzzzzzzzzz */
1123     eval(code.substring(0, code.length - 3) + ";}");
1124 };
1125
1126 // private
1127 Date.getFormatCode = function(character) {
1128     switch (character) {
1129     case "d":
1130         return "String.leftPad(this.getDate(), 2, '0') + ";
1131     case "D":
1132         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1133     case "j":
1134         return "this.getDate() + ";
1135     case "l":
1136         return "Date.dayNames[this.getDay()] + ";
1137     case "S":
1138         return "this.getSuffix() + ";
1139     case "w":
1140         return "this.getDay() + ";
1141     case "z":
1142         return "this.getDayOfYear() + ";
1143     case "W":
1144         return "this.getWeekOfYear() + ";
1145     case "F":
1146         return "Date.monthNames[this.getMonth()] + ";
1147     case "m":
1148         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1149     case "M":
1150         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1151     case "n":
1152         return "(this.getMonth() + 1) + ";
1153     case "t":
1154         return "this.getDaysInMonth() + ";
1155     case "L":
1156         return "(this.isLeapYear() ? 1 : 0) + ";
1157     case "Y":
1158         return "this.getFullYear() + ";
1159     case "y":
1160         return "('' + this.getFullYear()).substring(2, 4) + ";
1161     case "a":
1162         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1163     case "A":
1164         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1165     case "g":
1166         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1167     case "G":
1168         return "this.getHours() + ";
1169     case "h":
1170         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1171     case "H":
1172         return "String.leftPad(this.getHours(), 2, '0') + ";
1173     case "i":
1174         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1175     case "s":
1176         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1177     case "O":
1178         return "this.getGMTOffset() + ";
1179     case "P":
1180         return "this.getGMTColonOffset() + ";
1181     case "T":
1182         return "this.getTimezone() + ";
1183     case "Z":
1184         return "(this.getTimezoneOffset() * -60) + ";
1185     default:
1186         return "'" + String.escape(character) + "' + ";
1187     }
1188 };
1189
1190 /**
1191  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1193  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1194  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1195  * string or the parse operation will fail.
1196  * Example Usage:
1197 <pre><code>
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1200
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1203
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1206
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1209 </code></pre>
1210  * @param {String} input The unparsed date as a string
1211  * @param {String} format The format the date is in
1212  * @return {Date} The parsed date
1213  * @static
1214  */
1215 Date.parseDate = function(input, format) {
1216     if (Date.parseFunctions[format] == null) {
1217         Date.createParser(format);
1218     }
1219     var func = Date.parseFunctions[format];
1220     return Date[func](input);
1221 };
1222 /**
1223  * @private
1224  */
1225 Date.createParser = function(format) {
1226     var funcName = "parse" + Date.parseFunctions.count++;
1227     var regexNum = Date.parseRegexes.length;
1228     var currentGroup = 1;
1229     Date.parseFunctions[format] = funcName;
1230
1231     var code = "Date." + funcName + " = function(input){\n"
1232         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233         + "var d = new Date();\n"
1234         + "y = d.getFullYear();\n"
1235         + "m = d.getMonth();\n"
1236         + "d = d.getDate();\n"
1237         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238         + "if (results && results.length > 0) {";
1239     var regex = "";
1240
1241     var special = false;
1242     var ch = '';
1243     for (var i = 0; i < format.length; ++i) {
1244         ch = format.charAt(i);
1245         if (!special && ch == "\\") {
1246             special = true;
1247         }
1248         else if (special) {
1249             special = false;
1250             regex += String.escape(ch);
1251         }
1252         else {
1253             var obj = Date.formatCodeToRegex(ch, currentGroup);
1254             currentGroup += obj.g;
1255             regex += obj.s;
1256             if (obj.g && obj.c) {
1257                 code += obj.c;
1258             }
1259         }
1260     }
1261
1262     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i, s);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265         + "{v = new Date(y, m, d, h, i);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267         + "{v = new Date(y, m, d, h);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269         + "{v = new Date(y, m, d);}\n"
1270         + "else if (y >= 0 && m >= 0)\n"
1271         + "{v = new Date(y, m);}\n"
1272         + "else if (y >= 0)\n"
1273         + "{v = new Date(y);}\n"
1274         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277         + ";}";
1278
1279     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280     /** eval:var:zzzzzzzzzzzzz */
1281     eval(code);
1282 };
1283
1284 // private
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286     switch (character) {
1287     case "D":
1288         return {g:0,
1289         c:null,
1290         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291     case "j":
1292         return {g:1,
1293             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294             s:"(\\d{1,2})"}; // day of month without leading zeroes
1295     case "d":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{2})"}; // day of month with leading zeroes
1299     case "l":
1300         return {g:0,
1301             c:null,
1302             s:"(?:" + Date.dayNames.join("|") + ")"};
1303     case "S":
1304         return {g:0,
1305             c:null,
1306             s:"(?:st|nd|rd|th)"};
1307     case "w":
1308         return {g:0,
1309             c:null,
1310             s:"\\d"};
1311     case "z":
1312         return {g:0,
1313             c:null,
1314             s:"(?:\\d{1,3})"};
1315     case "W":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{2})"};
1319     case "F":
1320         return {g:1,
1321             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322             s:"(" + Date.monthNames.join("|") + ")"};
1323     case "M":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327     case "n":
1328         return {g:1,
1329             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331     case "m":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1335     case "t":
1336         return {g:0,
1337             c:null,
1338             s:"\\d{1,2}"};
1339     case "L":
1340         return {g:0,
1341             c:null,
1342             s:"(?:1|0)"};
1343     case "Y":
1344         return {g:1,
1345             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1346             s:"(\\d{4})"};
1347     case "y":
1348         return {g:1,
1349             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1351             s:"(\\d{1,2})"};
1352     case "a":
1353         return {g:1,
1354             c:"if (results[" + currentGroup + "] == 'am') {\n"
1355                 + "if (h == 12) { h = 0; }\n"
1356                 + "} else { if (h < 12) { h += 12; }}",
1357             s:"(am|pm)"};
1358     case "A":
1359         return {g:1,
1360             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361                 + "if (h == 12) { h = 0; }\n"
1362                 + "} else { if (h < 12) { h += 12; }}",
1363             s:"(AM|PM)"};
1364     case "g":
1365     case "G":
1366         return {g:1,
1367             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1369     case "h":
1370     case "H":
1371         return {g:1,
1372             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1374     case "i":
1375         return {g:1,
1376             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"};
1378     case "s":
1379         return {g:1,
1380             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "O":
1383         return {g:1,
1384             c:[
1385                 "o = results[", currentGroup, "];\n",
1386                 "var sn = o.substring(0,1);\n", // get + / - sign
1387                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391             ].join(""),
1392             s:"([+\-]\\d{2,4})"};
1393     
1394     
1395     case "P":
1396         return {g:1,
1397                 c:[
1398                    "o = results[", currentGroup, "];\n",
1399                    "var sn = o.substring(0,1);\n",
1400                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401                    "var mn = o.substring(4,6) % 60;\n",
1402                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1404             ].join(""),
1405             s:"([+\-]\\d{4})"};
1406     case "T":
1407         return {g:0,
1408             c:null,
1409             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410     case "Z":
1411         return {g:1,
1412             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1415     default:
1416         return {g:0,
1417             c:null,
1418             s:String.escape(character)};
1419     }
1420 };
1421
1422 /**
1423  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424  * @return {String} The abbreviated timezone name (e.g. 'CST')
1425  */
1426 Date.prototype.getTimezone = function() {
1427     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1428 };
1429
1430 /**
1431  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1433  */
1434 Date.prototype.getGMTOffset = function() {
1435     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1438 };
1439
1440 /**
1441  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442  * @return {String} 2-characters representing hours and 2-characters representing minutes
1443  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1444  */
1445 Date.prototype.getGMTColonOffset = function() {
1446         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1448                 + ":"
1449                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1450 }
1451
1452 /**
1453  * Get the numeric day number of the year, adjusted for leap year.
1454  * @return {Number} 0 through 364 (365 in leap years)
1455  */
1456 Date.prototype.getDayOfYear = function() {
1457     var num = 0;
1458     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459     for (var i = 0; i < this.getMonth(); ++i) {
1460         num += Date.daysInMonth[i];
1461     }
1462     return num + this.getDate() - 1;
1463 };
1464
1465 /**
1466  * Get the string representation of the numeric week number of the year
1467  * (equivalent to the format specifier 'W').
1468  * @return {String} '00' through '52'
1469  */
1470 Date.prototype.getWeekOfYear = function() {
1471     // Skip to Thursday of this week
1472     var now = this.getDayOfYear() + (4 - this.getDay());
1473     // Find the first Thursday of the year
1474     var jan1 = new Date(this.getFullYear(), 0, 1);
1475     var then = (7 - jan1.getDay() + 4);
1476     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1477 };
1478
1479 /**
1480  * Whether or not the current date is in a leap year.
1481  * @return {Boolean} True if the current date is in a leap year, else false
1482  */
1483 Date.prototype.isLeapYear = function() {
1484     var year = this.getFullYear();
1485     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1486 };
1487
1488 /**
1489  * Get the first day of the current month, adjusted for leap year.  The returned value
1490  * is the numeric day index within the week (0-6) which can be used in conjunction with
1491  * the {@link #monthNames} array to retrieve the textual day name.
1492  * Example:
1493  *<pre><code>
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1496 </code></pre>
1497  * @return {Number} The day number (0-6)
1498  */
1499 Date.prototype.getFirstDayOfMonth = function() {
1500     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501     return (day < 0) ? (day + 7) : day;
1502 };
1503
1504 /**
1505  * Get the last day of the current month, adjusted for leap year.  The returned value
1506  * is the numeric day index within the week (0-6) which can be used in conjunction with
1507  * the {@link #monthNames} array to retrieve the textual day name.
1508  * Example:
1509  *<pre><code>
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1512 </code></pre>
1513  * @return {Number} The day number (0-6)
1514  */
1515 Date.prototype.getLastDayOfMonth = function() {
1516     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517     return (day < 0) ? (day + 7) : day;
1518 };
1519
1520
1521 /**
1522  * Get the first date of this date's month
1523  * @return {Date}
1524  */
1525 Date.prototype.getFirstDateOfMonth = function() {
1526     return new Date(this.getFullYear(), this.getMonth(), 1);
1527 };
1528
1529 /**
1530  * Get the last date of this date's month
1531  * @return {Date}
1532  */
1533 Date.prototype.getLastDateOfMonth = function() {
1534     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 };
1536 /**
1537  * Get the number of days in the current month, adjusted for leap year.
1538  * @return {Number} The number of days in the month
1539  */
1540 Date.prototype.getDaysInMonth = function() {
1541     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542     return Date.daysInMonth[this.getMonth()];
1543 };
1544
1545 /**
1546  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547  * @return {String} 'st, 'nd', 'rd' or 'th'
1548  */
1549 Date.prototype.getSuffix = function() {
1550     switch (this.getDate()) {
1551         case 1:
1552         case 21:
1553         case 31:
1554             return "st";
1555         case 2:
1556         case 22:
1557             return "nd";
1558         case 3:
1559         case 23:
1560             return "rd";
1561         default:
1562             return "th";
1563     }
1564 };
1565
1566 // private
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568
1569 /**
1570  * An array of textual month names.
1571  * Override these values for international dates, for example...
1572  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1573  * @type Array
1574  * @static
1575  */
1576 Date.monthNames =
1577    ["January",
1578     "February",
1579     "March",
1580     "April",
1581     "May",
1582     "June",
1583     "July",
1584     "August",
1585     "September",
1586     "October",
1587     "November",
1588     "December"];
1589
1590 /**
1591  * An array of textual day names.
1592  * Override these values for international dates, for example...
1593  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1594  * @type Array
1595  * @static
1596  */
1597 Date.dayNames =
1598    ["Sunday",
1599     "Monday",
1600     "Tuesday",
1601     "Wednesday",
1602     "Thursday",
1603     "Friday",
1604     "Saturday"];
1605
1606 // private
1607 Date.y2kYear = 50;
1608 // private
1609 Date.monthNumbers = {
1610     Jan:0,
1611     Feb:1,
1612     Mar:2,
1613     Apr:3,
1614     May:4,
1615     Jun:5,
1616     Jul:6,
1617     Aug:7,
1618     Sep:8,
1619     Oct:9,
1620     Nov:10,
1621     Dec:11};
1622
1623 /**
1624  * Creates and returns a new Date instance with the exact same date value as the called instance.
1625  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626  * variable will also be changed.  When the intention is to create a new variable that will not
1627  * modify the original instance, you should create a clone.
1628  *
1629  * Example of correctly cloning a date:
1630  * <pre><code>
1631 //wrong way:
1632 var orig = new Date('10/1/2006');
1633 var copy = orig;
1634 copy.setDate(5);
1635 document.write(orig);  //returns 'Thu Oct 05 2006'!
1636
1637 //correct way:
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1640 copy.setDate(5);
1641 document.write(orig);  //returns 'Thu Oct 01 2006'
1642 </code></pre>
1643  * @return {Date} The new Date instance
1644  */
1645 Date.prototype.clone = function() {
1646         return new Date(this.getTime());
1647 };
1648
1649 /**
1650  * Clears any time information from this date
1651  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652  @return {Date} this or the clone
1653  */
1654 Date.prototype.clearTime = function(clone){
1655     if(clone){
1656         return this.clone().clearTime();
1657     }
1658     this.setHours(0);
1659     this.setMinutes(0);
1660     this.setSeconds(0);
1661     this.setMilliseconds(0);
1662     return this;
1663 };
1664
1665 // private
1666 // safari setMonth is broken
1667 if(Roo.isSafari){
1668     Date.brokenSetMonth = Date.prototype.setMonth;
1669         Date.prototype.setMonth = function(num){
1670                 if(num <= -1){
1671                         var n = Math.ceil(-num);
1672                         var back_year = Math.ceil(n/12);
1673                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1674                         this.setFullYear(this.getFullYear() - back_year);
1675                         return Date.brokenSetMonth.call(this, month);
1676                 } else {
1677                         return Date.brokenSetMonth.apply(this, arguments);
1678                 }
1679         };
1680 }
1681
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.MILLI = "ms";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.SECOND = "s";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.MINUTE = "mi";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.HOUR = "h";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.DAY = "d";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MONTH = "mo";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.YEAR = "y";
1710
1711 /**
1712  * Provides a convenient method of performing basic date arithmetic.  This method
1713  * does not modify the Date instance being called - it creates and returns
1714  * a new Date instance containing the resulting date value.
1715  *
1716  * Examples:
1717  * <pre><code>
1718 //Basic usage:
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1721
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1725
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729  </code></pre>
1730  *
1731  * @param {String} interval   A valid date interval enum value
1732  * @param {Number} value      The amount to add to the current date
1733  * @return {Date} The new Date instance
1734  */
1735 Date.prototype.add = function(interval, value){
1736   var d = this.clone();
1737   if (!interval || value === 0) return d;
1738   switch(interval.toLowerCase()){
1739     case Date.MILLI:
1740       d.setMilliseconds(this.getMilliseconds() + value);
1741       break;
1742     case Date.SECOND:
1743       d.setSeconds(this.getSeconds() + value);
1744       break;
1745     case Date.MINUTE:
1746       d.setMinutes(this.getMinutes() + value);
1747       break;
1748     case Date.HOUR:
1749       d.setHours(this.getHours() + value);
1750       break;
1751     case Date.DAY:
1752       d.setDate(this.getDate() + value);
1753       break;
1754     case Date.MONTH:
1755       var day = this.getDate();
1756       if(day > 28){
1757           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758       }
1759       d.setDate(day);
1760       d.setMonth(this.getMonth() + value);
1761       break;
1762     case Date.YEAR:
1763       d.setFullYear(this.getFullYear() + value);
1764       break;
1765   }
1766   return d;
1767 };
1768 /*
1769  * Based on:
1770  * Ext JS Library 1.1.1
1771  * Copyright(c) 2006-2007, Ext JS, LLC.
1772  *
1773  * Originally Released Under LGPL - original licence link has changed is not relivant.
1774  *
1775  * Fork - LGPL
1776  * <script type="text/javascript">
1777  */
1778
1779 /**
1780  * @class Roo.lib.Dom
1781  * @static
1782  * 
1783  * Dom utils (from YIU afaik)
1784  * 
1785  **/
1786 Roo.lib.Dom = {
1787     /**
1788      * Get the view width
1789      * @param {Boolean} full True will get the full document, otherwise it's the view width
1790      * @return {Number} The width
1791      */
1792      
1793     getViewWidth : function(full) {
1794         return full ? this.getDocumentWidth() : this.getViewportWidth();
1795     },
1796     /**
1797      * Get the view height
1798      * @param {Boolean} full True will get the full document, otherwise it's the view height
1799      * @return {Number} The height
1800      */
1801     getViewHeight : function(full) {
1802         return full ? this.getDocumentHeight() : this.getViewportHeight();
1803     },
1804
1805     getDocumentHeight: function() {
1806         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807         return Math.max(scrollHeight, this.getViewportHeight());
1808     },
1809
1810     getDocumentWidth: function() {
1811         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812         return Math.max(scrollWidth, this.getViewportWidth());
1813     },
1814
1815     getViewportHeight: function() {
1816         var height = self.innerHeight;
1817         var mode = document.compatMode;
1818
1819         if ((mode || Roo.isIE) && !Roo.isOpera) {
1820             height = (mode == "CSS1Compat") ?
1821                      document.documentElement.clientHeight :
1822                      document.body.clientHeight;
1823         }
1824
1825         return height;
1826     },
1827
1828     getViewportWidth: function() {
1829         var width = self.innerWidth;
1830         var mode = document.compatMode;
1831
1832         if (mode || Roo.isIE) {
1833             width = (mode == "CSS1Compat") ?
1834                     document.documentElement.clientWidth :
1835                     document.body.clientWidth;
1836         }
1837         return width;
1838     },
1839
1840     isAncestor : function(p, c) {
1841         p = Roo.getDom(p);
1842         c = Roo.getDom(c);
1843         if (!p || !c) {
1844             return false;
1845         }
1846
1847         if (p.contains && !Roo.isSafari) {
1848             return p.contains(c);
1849         } else if (p.compareDocumentPosition) {
1850             return !!(p.compareDocumentPosition(c) & 16);
1851         } else {
1852             var parent = c.parentNode;
1853             while (parent) {
1854                 if (parent == p) {
1855                     return true;
1856                 }
1857                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858                     return false;
1859                 }
1860                 parent = parent.parentNode;
1861             }
1862             return false;
1863         }
1864     },
1865
1866     getRegion : function(el) {
1867         return Roo.lib.Region.getRegion(el);
1868     },
1869
1870     getY : function(el) {
1871         return this.getXY(el)[1];
1872     },
1873
1874     getX : function(el) {
1875         return this.getXY(el)[0];
1876     },
1877
1878     getXY : function(el) {
1879         var p, pe, b, scroll, bd = document.body;
1880         el = Roo.getDom(el);
1881         var fly = Roo.lib.AnimBase.fly;
1882         if (el.getBoundingClientRect) {
1883             b = el.getBoundingClientRect();
1884             scroll = fly(document).getScroll();
1885             return [b.left + scroll.left, b.top + scroll.top];
1886         }
1887         var x = 0, y = 0;
1888
1889         p = el;
1890
1891         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1892
1893         while (p) {
1894
1895             x += p.offsetLeft;
1896             y += p.offsetTop;
1897
1898             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1899                 hasAbsolute = true;
1900             }
1901
1902             if (Roo.isGecko) {
1903                 pe = fly(p);
1904
1905                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1907
1908
1909                 x += bl;
1910                 y += bt;
1911
1912
1913                 if (p != el && pe.getStyle('overflow') != 'visible') {
1914                     x += bl;
1915                     y += bt;
1916                 }
1917             }
1918             p = p.offsetParent;
1919         }
1920
1921         if (Roo.isSafari && hasAbsolute) {
1922             x -= bd.offsetLeft;
1923             y -= bd.offsetTop;
1924         }
1925
1926         if (Roo.isGecko && !hasAbsolute) {
1927             var dbd = fly(bd);
1928             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1930         }
1931
1932         p = el.parentNode;
1933         while (p && p != bd) {
1934             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1935                 x -= p.scrollLeft;
1936                 y -= p.scrollTop;
1937             }
1938             p = p.parentNode;
1939         }
1940         return [x, y];
1941     },
1942  
1943   
1944
1945
1946     setXY : function(el, xy) {
1947         el = Roo.fly(el, '_setXY');
1948         el.position();
1949         var pts = el.translatePoints(xy);
1950         if (xy[0] !== false) {
1951             el.dom.style.left = pts.left + "px";
1952         }
1953         if (xy[1] !== false) {
1954             el.dom.style.top = pts.top + "px";
1955         }
1956     },
1957
1958     setX : function(el, x) {
1959         this.setXY(el, [x, false]);
1960     },
1961
1962     setY : function(el, y) {
1963         this.setXY(el, [false, y]);
1964     }
1965 };
1966 /*
1967  * Portions of this file are based on pieces of Yahoo User Interface Library
1968  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969  * YUI licensed under the BSD License:
1970  * http://developer.yahoo.net/yui/license.txt
1971  * <script type="text/javascript">
1972  *
1973  */
1974
1975 Roo.lib.Event = function() {
1976     var loadComplete = false;
1977     var listeners = [];
1978     var unloadListeners = [];
1979     var retryCount = 0;
1980     var onAvailStack = [];
1981     var counter = 0;
1982     var lastError = null;
1983
1984     return {
1985         POLL_RETRYS: 200,
1986         POLL_INTERVAL: 20,
1987         EL: 0,
1988         TYPE: 1,
1989         FN: 2,
1990         WFN: 3,
1991         OBJ: 3,
1992         ADJ_SCOPE: 4,
1993         _interval: null,
1994
1995         startInterval: function() {
1996             if (!this._interval) {
1997                 var self = this;
1998                 var callback = function() {
1999                     self._tryPreloadAttach();
2000                 };
2001                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2002
2003             }
2004         },
2005
2006         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007             onAvailStack.push({ id:         p_id,
2008                 fn:         p_fn,
2009                 obj:        p_obj,
2010                 override:   p_override,
2011                 checkReady: false    });
2012
2013             retryCount = this.POLL_RETRYS;
2014             this.startInterval();
2015         },
2016
2017
2018         addListener: function(el, eventName, fn) {
2019             el = Roo.getDom(el);
2020             if (!el || !fn) {
2021                 return false;
2022             }
2023
2024             if ("unload" == eventName) {
2025                 unloadListeners[unloadListeners.length] =
2026                 [el, eventName, fn];
2027                 return true;
2028             }
2029
2030             var wrappedFn = function(e) {
2031                 return fn(Roo.lib.Event.getEvent(e));
2032             };
2033
2034             var li = [el, eventName, fn, wrappedFn];
2035
2036             var index = listeners.length;
2037             listeners[index] = li;
2038
2039             this.doAdd(el, eventName, wrappedFn, false);
2040             return true;
2041
2042         },
2043
2044
2045         removeListener: function(el, eventName, fn) {
2046             var i, len;
2047
2048             el = Roo.getDom(el);
2049
2050             if(!fn) {
2051                 return this.purgeElement(el, false, eventName);
2052             }
2053
2054
2055             if ("unload" == eventName) {
2056
2057                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058                     var li = unloadListeners[i];
2059                     if (li &&
2060                         li[0] == el &&
2061                         li[1] == eventName &&
2062                         li[2] == fn) {
2063                         unloadListeners.splice(i, 1);
2064                         return true;
2065                     }
2066                 }
2067
2068                 return false;
2069             }
2070
2071             var cacheItem = null;
2072
2073
2074             var index = arguments[3];
2075
2076             if ("undefined" == typeof index) {
2077                 index = this._getCacheIndex(el, eventName, fn);
2078             }
2079
2080             if (index >= 0) {
2081                 cacheItem = listeners[index];
2082             }
2083
2084             if (!el || !cacheItem) {
2085                 return false;
2086             }
2087
2088             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2089
2090             delete listeners[index][this.WFN];
2091             delete listeners[index][this.FN];
2092             listeners.splice(index, 1);
2093
2094             return true;
2095
2096         },
2097
2098
2099         getTarget: function(ev, resolveTextNode) {
2100             ev = ev.browserEvent || ev;
2101             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2102             var t = ev.target || ev.srcElement;
2103             return this.resolveTextNode(t);
2104         },
2105
2106
2107         resolveTextNode: function(node) {
2108             if (Roo.isSafari && node && 3 == node.nodeType) {
2109                 return node.parentNode;
2110             } else {
2111                 return node;
2112             }
2113         },
2114
2115
2116         getPageX: function(ev) {
2117             ev = ev.browserEvent || ev;
2118             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2119             var x = ev.pageX;
2120             if (!x && 0 !== x) {
2121                 x = ev.clientX || 0;
2122
2123                 if (Roo.isIE) {
2124                     x += this.getScroll()[1];
2125                 }
2126             }
2127
2128             return x;
2129         },
2130
2131
2132         getPageY: function(ev) {
2133             ev = ev.browserEvent || ev;
2134             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2135             var y = ev.pageY;
2136             if (!y && 0 !== y) {
2137                 y = ev.clientY || 0;
2138
2139                 if (Roo.isIE) {
2140                     y += this.getScroll()[0];
2141                 }
2142             }
2143
2144
2145             return y;
2146         },
2147
2148
2149         getXY: function(ev) {
2150             ev = ev.browserEvent || ev;
2151             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2152             return [this.getPageX(ev), this.getPageY(ev)];
2153         },
2154
2155
2156         getRelatedTarget: function(ev) {
2157             ev = ev.browserEvent || ev;
2158             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2159             var t = ev.relatedTarget;
2160             if (!t) {
2161                 if (ev.type == "mouseout") {
2162                     t = ev.toElement;
2163                 } else if (ev.type == "mouseover") {
2164                     t = ev.fromElement;
2165                 }
2166             }
2167
2168             return this.resolveTextNode(t);
2169         },
2170
2171
2172         getTime: function(ev) {
2173             ev = ev.browserEvent || ev;
2174             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2175             if (!ev.time) {
2176                 var t = new Date().getTime();
2177                 try {
2178                     ev.time = t;
2179                 } catch(ex) {
2180                     this.lastError = ex;
2181                     return t;
2182                 }
2183             }
2184
2185             return ev.time;
2186         },
2187
2188
2189         stopEvent: function(ev) {
2190             this.stopPropagation(ev);
2191             this.preventDefault(ev);
2192         },
2193
2194
2195         stopPropagation: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             if (ev.stopPropagation) {
2198                 ev.stopPropagation();
2199             } else {
2200                 ev.cancelBubble = true;
2201             }
2202         },
2203
2204
2205         preventDefault: function(ev) {
2206             ev = ev.browserEvent || ev;
2207             if(ev.preventDefault) {
2208                 ev.preventDefault();
2209             } else {
2210                 ev.returnValue = false;
2211             }
2212         },
2213
2214
2215         getEvent: function(e) {
2216             var ev = e || window.event;
2217             if (!ev) {
2218                 var c = this.getEvent.caller;
2219                 while (c) {
2220                     ev = c.arguments[0];
2221                     if (ev && Event == ev.constructor) {
2222                         break;
2223                     }
2224                     c = c.caller;
2225                 }
2226             }
2227             return ev;
2228         },
2229
2230
2231         getCharCode: function(ev) {
2232             ev = ev.browserEvent || ev;
2233             return ev.charCode || ev.keyCode || 0;
2234         },
2235
2236
2237         _getCacheIndex: function(el, eventName, fn) {
2238             for (var i = 0,len = listeners.length; i < len; ++i) {
2239                 var li = listeners[i];
2240                 if (li &&
2241                     li[this.FN] == fn &&
2242                     li[this.EL] == el &&
2243                     li[this.TYPE] == eventName) {
2244                     return i;
2245                 }
2246             }
2247
2248             return -1;
2249         },
2250
2251
2252         elCache: {},
2253
2254
2255         getEl: function(id) {
2256             return document.getElementById(id);
2257         },
2258
2259
2260         clearCache: function() {
2261         },
2262
2263
2264         _load: function(e) {
2265             loadComplete = true;
2266             var EU = Roo.lib.Event;
2267
2268
2269             if (Roo.isIE) {
2270                 EU.doRemove(window, "load", EU._load);
2271             }
2272         },
2273
2274
2275         _tryPreloadAttach: function() {
2276
2277             if (this.locked) {
2278                 return false;
2279             }
2280
2281             this.locked = true;
2282
2283
2284             var tryAgain = !loadComplete;
2285             if (!tryAgain) {
2286                 tryAgain = (retryCount > 0);
2287             }
2288
2289
2290             var notAvail = [];
2291             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292                 var item = onAvailStack[i];
2293                 if (item) {
2294                     var el = this.getEl(item.id);
2295
2296                     if (el) {
2297                         if (!item.checkReady ||
2298                             loadComplete ||
2299                             el.nextSibling ||
2300                             (document && document.body)) {
2301
2302                             var scope = el;
2303                             if (item.override) {
2304                                 if (item.override === true) {
2305                                     scope = item.obj;
2306                                 } else {
2307                                     scope = item.override;
2308                                 }
2309                             }
2310                             item.fn.call(scope, item.obj);
2311                             onAvailStack[i] = null;
2312                         }
2313                     } else {
2314                         notAvail.push(item);
2315                     }
2316                 }
2317             }
2318
2319             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2320
2321             if (tryAgain) {
2322
2323                 this.startInterval();
2324             } else {
2325                 clearInterval(this._interval);
2326                 this._interval = null;
2327             }
2328
2329             this.locked = false;
2330
2331             return true;
2332
2333         },
2334
2335
2336         purgeElement: function(el, recurse, eventName) {
2337             var elListeners = this.getListeners(el, eventName);
2338             if (elListeners) {
2339                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340                     var l = elListeners[i];
2341                     this.removeListener(el, l.type, l.fn);
2342                 }
2343             }
2344
2345             if (recurse && el && el.childNodes) {
2346                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347                     this.purgeElement(el.childNodes[i], recurse, eventName);
2348                 }
2349             }
2350         },
2351
2352
2353         getListeners: function(el, eventName) {
2354             var results = [], searchLists;
2355             if (!eventName) {
2356                 searchLists = [listeners, unloadListeners];
2357             } else if (eventName == "unload") {
2358                 searchLists = [unloadListeners];
2359             } else {
2360                 searchLists = [listeners];
2361             }
2362
2363             for (var j = 0; j < searchLists.length; ++j) {
2364                 var searchList = searchLists[j];
2365                 if (searchList && searchList.length > 0) {
2366                     for (var i = 0,len = searchList.length; i < len; ++i) {
2367                         var l = searchList[i];
2368                         if (l && l[this.EL] === el &&
2369                             (!eventName || eventName === l[this.TYPE])) {
2370                             results.push({
2371                                 type:   l[this.TYPE],
2372                                 fn:     l[this.FN],
2373                                 obj:    l[this.OBJ],
2374                                 adjust: l[this.ADJ_SCOPE],
2375                                 index:  i
2376                             });
2377                         }
2378                     }
2379                 }
2380             }
2381
2382             return (results.length) ? results : null;
2383         },
2384
2385
2386         _unload: function(e) {
2387
2388             var EU = Roo.lib.Event, i, j, l, len, index;
2389
2390             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391                 l = unloadListeners[i];
2392                 if (l) {
2393                     var scope = window;
2394                     if (l[EU.ADJ_SCOPE]) {
2395                         if (l[EU.ADJ_SCOPE] === true) {
2396                             scope = l[EU.OBJ];
2397                         } else {
2398                             scope = l[EU.ADJ_SCOPE];
2399                         }
2400                     }
2401                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402                     unloadListeners[i] = null;
2403                     l = null;
2404                     scope = null;
2405                 }
2406             }
2407
2408             unloadListeners = null;
2409
2410             if (listeners && listeners.length > 0) {
2411                 j = listeners.length;
2412                 while (j) {
2413                     index = j - 1;
2414                     l = listeners[index];
2415                     if (l) {
2416                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2417                                 l[EU.FN], index);
2418                     }
2419                     j = j - 1;
2420                 }
2421                 l = null;
2422
2423                 EU.clearCache();
2424             }
2425
2426             EU.doRemove(window, "unload", EU._unload);
2427
2428         },
2429
2430
2431         getScroll: function() {
2432             var dd = document.documentElement, db = document.body;
2433             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434                 return [dd.scrollTop, dd.scrollLeft];
2435             } else if (db) {
2436                 return [db.scrollTop, db.scrollLeft];
2437             } else {
2438                 return [0, 0];
2439             }
2440         },
2441
2442
2443         doAdd: function () {
2444             if (window.addEventListener) {
2445                 return function(el, eventName, fn, capture) {
2446                     el.addEventListener(eventName, fn, (capture));
2447                 };
2448             } else if (window.attachEvent) {
2449                 return function(el, eventName, fn, capture) {
2450                     el.attachEvent("on" + eventName, fn);
2451                 };
2452             } else {
2453                 return function() {
2454                 };
2455             }
2456         }(),
2457
2458
2459         doRemove: function() {
2460             if (window.removeEventListener) {
2461                 return function (el, eventName, fn, capture) {
2462                     el.removeEventListener(eventName, fn, (capture));
2463                 };
2464             } else if (window.detachEvent) {
2465                 return function (el, eventName, fn) {
2466                     el.detachEvent("on" + eventName, fn);
2467                 };
2468             } else {
2469                 return function() {
2470                 };
2471             }
2472         }()
2473     };
2474     
2475 }();
2476 (function() {     
2477    
2478     var E = Roo.lib.Event;
2479     E.on = E.addListener;
2480     E.un = E.removeListener;
2481
2482     if (document && document.body) {
2483         E._load();
2484     } else {
2485         E.doAdd(window, "load", E._load);
2486     }
2487     E.doAdd(window, "unload", E._unload);
2488     E._tryPreloadAttach();
2489 })();
2490
2491 /*
2492  * Portions of this file are based on pieces of Yahoo User Interface Library
2493  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494  * YUI licensed under the BSD License:
2495  * http://developer.yahoo.net/yui/license.txt
2496  * <script type="text/javascript">
2497  *
2498  */
2499
2500 (function() {
2501     /**
2502      * @class Roo.lib.Ajax
2503      *
2504      */
2505     Roo.lib.Ajax = {
2506         /**
2507          * @static 
2508          */
2509         request : function(method, uri, cb, data, options) {
2510             if(options){
2511                 var hs = options.headers;
2512                 if(hs){
2513                     for(var h in hs){
2514                         if(hs.hasOwnProperty(h)){
2515                             this.initHeader(h, hs[h], false);
2516                         }
2517                     }
2518                 }
2519                 if(options.xmlData){
2520                     this.initHeader('Content-Type', 'text/xml', false);
2521                     method = 'POST';
2522                     data = options.xmlData;
2523                 }
2524             }
2525
2526             return this.asyncRequest(method, uri, cb, data);
2527         },
2528
2529         serializeForm : function(form) {
2530             if(typeof form == 'string') {
2531                 form = (document.getElementById(form) || document.forms[form]);
2532             }
2533
2534             var el, name, val, disabled, data = '', hasSubmit = false;
2535             for (var i = 0; i < form.elements.length; i++) {
2536                 el = form.elements[i];
2537                 disabled = form.elements[i].disabled;
2538                 name = form.elements[i].name;
2539                 val = form.elements[i].value;
2540
2541                 if (!disabled && name){
2542                     switch (el.type)
2543                             {
2544                         case 'select-one':
2545                         case 'select-multiple':
2546                             for (var j = 0; j < el.options.length; j++) {
2547                                 if (el.options[j].selected) {
2548                                     if (Roo.isIE) {
2549                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2550                                     }
2551                                     else {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                 }
2555                             }
2556                             break;
2557                         case 'radio':
2558                         case 'checkbox':
2559                             if (el.checked) {
2560                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2561                             }
2562                             break;
2563                         case 'file':
2564
2565                         case undefined:
2566
2567                         case 'reset':
2568
2569                         case 'button':
2570
2571                             break;
2572                         case 'submit':
2573                             if(hasSubmit == false) {
2574                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2575                                 hasSubmit = true;
2576                             }
2577                             break;
2578                         default:
2579                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2580                             break;
2581                     }
2582                 }
2583             }
2584             data = data.substr(0, data.length - 1);
2585             return data;
2586         },
2587
2588         headers:{},
2589
2590         hasHeaders:false,
2591
2592         useDefaultHeader:true,
2593
2594         defaultPostHeader:'application/x-www-form-urlencoded',
2595
2596         useDefaultXhrHeader:true,
2597
2598         defaultXhrHeader:'XMLHttpRequest',
2599
2600         hasDefaultHeaders:true,
2601
2602         defaultHeaders:{},
2603
2604         poll:{},
2605
2606         timeout:{},
2607
2608         pollInterval:50,
2609
2610         transactionId:0,
2611
2612         setProgId:function(id)
2613         {
2614             this.activeX.unshift(id);
2615         },
2616
2617         setDefaultPostHeader:function(b)
2618         {
2619             this.useDefaultHeader = b;
2620         },
2621
2622         setDefaultXhrHeader:function(b)
2623         {
2624             this.useDefaultXhrHeader = b;
2625         },
2626
2627         setPollingInterval:function(i)
2628         {
2629             if (typeof i == 'number' && isFinite(i)) {
2630                 this.pollInterval = i;
2631             }
2632         },
2633
2634         createXhrObject:function(transactionId)
2635         {
2636             var obj,http;
2637             try
2638             {
2639
2640                 http = new XMLHttpRequest();
2641
2642                 obj = { conn:http, tId:transactionId };
2643             }
2644             catch(e)
2645             {
2646                 for (var i = 0; i < this.activeX.length; ++i) {
2647                     try
2648                     {
2649
2650                         http = new ActiveXObject(this.activeX[i]);
2651
2652                         obj = { conn:http, tId:transactionId };
2653                         break;
2654                     }
2655                     catch(e) {
2656                     }
2657                 }
2658             }
2659             finally
2660             {
2661                 return obj;
2662             }
2663         },
2664
2665         getConnectionObject:function()
2666         {
2667             var o;
2668             var tId = this.transactionId;
2669
2670             try
2671             {
2672                 o = this.createXhrObject(tId);
2673                 if (o) {
2674                     this.transactionId++;
2675                 }
2676             }
2677             catch(e) {
2678             }
2679             finally
2680             {
2681                 return o;
2682             }
2683         },
2684
2685         asyncRequest:function(method, uri, callback, postData)
2686         {
2687             var o = this.getConnectionObject();
2688
2689             if (!o) {
2690                 return null;
2691             }
2692             else {
2693                 o.conn.open(method, uri, true);
2694
2695                 if (this.useDefaultXhrHeader) {
2696                     if (!this.defaultHeaders['X-Requested-With']) {
2697                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2698                     }
2699                 }
2700
2701                 if(postData && this.useDefaultHeader){
2702                     this.initHeader('Content-Type', this.defaultPostHeader);
2703                 }
2704
2705                  if (this.hasDefaultHeaders || this.hasHeaders) {
2706                     this.setHeader(o);
2707                 }
2708
2709                 this.handleReadyState(o, callback);
2710                 o.conn.send(postData || null);
2711
2712                 return o;
2713             }
2714         },
2715
2716         handleReadyState:function(o, callback)
2717         {
2718             var oConn = this;
2719
2720             if (callback && callback.timeout) {
2721                 
2722                 this.timeout[o.tId] = window.setTimeout(function() {
2723                     oConn.abort(o, callback, true);
2724                 }, callback.timeout);
2725             }
2726
2727             this.poll[o.tId] = window.setInterval(
2728                     function() {
2729                         if (o.conn && o.conn.readyState == 4) {
2730                             window.clearInterval(oConn.poll[o.tId]);
2731                             delete oConn.poll[o.tId];
2732
2733                             if(callback && callback.timeout) {
2734                                 window.clearTimeout(oConn.timeout[o.tId]);
2735                                 delete oConn.timeout[o.tId];
2736                             }
2737
2738                             oConn.handleTransactionResponse(o, callback);
2739                         }
2740                     }
2741                     , this.pollInterval);
2742         },
2743
2744         handleTransactionResponse:function(o, callback, isAbort)
2745         {
2746
2747             if (!callback) {
2748                 this.releaseObject(o);
2749                 return;
2750             }
2751
2752             var httpStatus, responseObject;
2753
2754             try
2755             {
2756                 if (o.conn.status !== undefined && o.conn.status != 0) {
2757                     httpStatus = o.conn.status;
2758                 }
2759                 else {
2760                     httpStatus = 13030;
2761                 }
2762             }
2763             catch(e) {
2764
2765
2766                 httpStatus = 13030;
2767             }
2768
2769             if (httpStatus >= 200 && httpStatus < 300) {
2770                 responseObject = this.createResponseObject(o, callback.argument);
2771                 if (callback.success) {
2772                     if (!callback.scope) {
2773                         callback.success(responseObject);
2774                     }
2775                     else {
2776
2777
2778                         callback.success.apply(callback.scope, [responseObject]);
2779                     }
2780                 }
2781             }
2782             else {
2783                 switch (httpStatus) {
2784
2785                     case 12002:
2786                     case 12029:
2787                     case 12030:
2788                     case 12031:
2789                     case 12152:
2790                     case 13030:
2791                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792                         if (callback.failure) {
2793                             if (!callback.scope) {
2794                                 callback.failure(responseObject);
2795                             }
2796                             else {
2797                                 callback.failure.apply(callback.scope, [responseObject]);
2798                             }
2799                         }
2800                         break;
2801                     default:
2802                         responseObject = this.createResponseObject(o, callback.argument);
2803                         if (callback.failure) {
2804                             if (!callback.scope) {
2805                                 callback.failure(responseObject);
2806                             }
2807                             else {
2808                                 callback.failure.apply(callback.scope, [responseObject]);
2809                             }
2810                         }
2811                 }
2812             }
2813
2814             this.releaseObject(o);
2815             responseObject = null;
2816         },
2817
2818         createResponseObject:function(o, callbackArg)
2819         {
2820             var obj = {};
2821             var headerObj = {};
2822
2823             try
2824             {
2825                 var headerStr = o.conn.getAllResponseHeaders();
2826                 var header = headerStr.split('\n');
2827                 for (var i = 0; i < header.length; i++) {
2828                     var delimitPos = header[i].indexOf(':');
2829                     if (delimitPos != -1) {
2830                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2831                     }
2832                 }
2833             }
2834             catch(e) {
2835             }
2836
2837             obj.tId = o.tId;
2838             obj.status = o.conn.status;
2839             obj.statusText = o.conn.statusText;
2840             obj.getResponseHeader = headerObj;
2841             obj.getAllResponseHeaders = headerStr;
2842             obj.responseText = o.conn.responseText;
2843             obj.responseXML = o.conn.responseXML;
2844
2845             if (typeof callbackArg !== undefined) {
2846                 obj.argument = callbackArg;
2847             }
2848
2849             return obj;
2850         },
2851
2852         createExceptionObject:function(tId, callbackArg, isAbort)
2853         {
2854             var COMM_CODE = 0;
2855             var COMM_ERROR = 'communication failure';
2856             var ABORT_CODE = -1;
2857             var ABORT_ERROR = 'transaction aborted';
2858
2859             var obj = {};
2860
2861             obj.tId = tId;
2862             if (isAbort) {
2863                 obj.status = ABORT_CODE;
2864                 obj.statusText = ABORT_ERROR;
2865             }
2866             else {
2867                 obj.status = COMM_CODE;
2868                 obj.statusText = COMM_ERROR;
2869             }
2870
2871             if (callbackArg) {
2872                 obj.argument = callbackArg;
2873             }
2874
2875             return obj;
2876         },
2877
2878         initHeader:function(label, value, isDefault)
2879         {
2880             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2881
2882             if (headerObj[label] === undefined) {
2883                 headerObj[label] = value;
2884             }
2885             else {
2886
2887
2888                 headerObj[label] = value + "," + headerObj[label];
2889             }
2890
2891             if (isDefault) {
2892                 this.hasDefaultHeaders = true;
2893             }
2894             else {
2895                 this.hasHeaders = true;
2896             }
2897         },
2898
2899
2900         setHeader:function(o)
2901         {
2902             if (this.hasDefaultHeaders) {
2903                 for (var prop in this.defaultHeaders) {
2904                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2905                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2906                     }
2907                 }
2908             }
2909
2910             if (this.hasHeaders) {
2911                 for (var prop in this.headers) {
2912                     if (this.headers.hasOwnProperty(prop)) {
2913                         o.conn.setRequestHeader(prop, this.headers[prop]);
2914                     }
2915                 }
2916                 this.headers = {};
2917                 this.hasHeaders = false;
2918             }
2919         },
2920
2921         resetDefaultHeaders:function() {
2922             delete this.defaultHeaders;
2923             this.defaultHeaders = {};
2924             this.hasDefaultHeaders = false;
2925         },
2926
2927         abort:function(o, callback, isTimeout)
2928         {
2929             if(this.isCallInProgress(o)) {
2930                 o.conn.abort();
2931                 window.clearInterval(this.poll[o.tId]);
2932                 delete this.poll[o.tId];
2933                 if (isTimeout) {
2934                     delete this.timeout[o.tId];
2935                 }
2936
2937                 this.handleTransactionResponse(o, callback, true);
2938
2939                 return true;
2940             }
2941             else {
2942                 return false;
2943             }
2944         },
2945
2946
2947         isCallInProgress:function(o)
2948         {
2949             if (o && o.conn) {
2950                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2951             }
2952             else {
2953
2954                 return false;
2955             }
2956         },
2957
2958
2959         releaseObject:function(o)
2960         {
2961
2962             o.conn = null;
2963
2964             o = null;
2965         },
2966
2967         activeX:[
2968         'MSXML2.XMLHTTP.3.0',
2969         'MSXML2.XMLHTTP',
2970         'Microsoft.XMLHTTP'
2971         ]
2972
2973
2974     };
2975 })();/*
2976  * Portions of this file are based on pieces of Yahoo User Interface Library
2977  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978  * YUI licensed under the BSD License:
2979  * http://developer.yahoo.net/yui/license.txt
2980  * <script type="text/javascript">
2981  *
2982  */
2983
2984 Roo.lib.Region = function(t, r, b, l) {
2985     this.top = t;
2986     this[1] = t;
2987     this.right = r;
2988     this.bottom = b;
2989     this.left = l;
2990     this[0] = l;
2991 };
2992
2993
2994 Roo.lib.Region.prototype = {
2995     contains : function(region) {
2996         return ( region.left >= this.left &&
2997                  region.right <= this.right &&
2998                  region.top >= this.top &&
2999                  region.bottom <= this.bottom    );
3000
3001     },
3002
3003     getArea : function() {
3004         return ( (this.bottom - this.top) * (this.right - this.left) );
3005     },
3006
3007     intersect : function(region) {
3008         var t = Math.max(this.top, region.top);
3009         var r = Math.min(this.right, region.right);
3010         var b = Math.min(this.bottom, region.bottom);
3011         var l = Math.max(this.left, region.left);
3012
3013         if (b >= t && r >= l) {
3014             return new Roo.lib.Region(t, r, b, l);
3015         } else {
3016             return null;
3017         }
3018     },
3019     union : function(region) {
3020         var t = Math.min(this.top, region.top);
3021         var r = Math.max(this.right, region.right);
3022         var b = Math.max(this.bottom, region.bottom);
3023         var l = Math.min(this.left, region.left);
3024
3025         return new Roo.lib.Region(t, r, b, l);
3026     },
3027
3028     adjust : function(t, l, b, r) {
3029         this.top += t;
3030         this.left += l;
3031         this.right += r;
3032         this.bottom += b;
3033         return this;
3034     }
3035 };
3036
3037 Roo.lib.Region.getRegion = function(el) {
3038     var p = Roo.lib.Dom.getXY(el);
3039
3040     var t = p[1];
3041     var r = p[0] + el.offsetWidth;
3042     var b = p[1] + el.offsetHeight;
3043     var l = p[0];
3044
3045     return new Roo.lib.Region(t, r, b, l);
3046 };
3047 /*
3048  * Portions of this file are based on pieces of Yahoo User Interface Library
3049  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050  * YUI licensed under the BSD License:
3051  * http://developer.yahoo.net/yui/license.txt
3052  * <script type="text/javascript">
3053  *
3054  */
3055 //@@dep Roo.lib.Region
3056
3057
3058 Roo.lib.Point = function(x, y) {
3059     if (x instanceof Array) {
3060         y = x[1];
3061         x = x[0];
3062     }
3063     this.x = this.right = this.left = this[0] = x;
3064     this.y = this.top = this.bottom = this[1] = y;
3065 };
3066
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3068 /*
3069  * Portions of this file are based on pieces of Yahoo User Interface Library
3070  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071  * YUI licensed under the BSD License:
3072  * http://developer.yahoo.net/yui/license.txt
3073  * <script type="text/javascript">
3074  *
3075  */
3076  
3077 (function() {   
3078
3079     Roo.lib.Anim = {
3080         scroll : function(el, args, duration, easing, cb, scope) {
3081             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3082         },
3083
3084         motion : function(el, args, duration, easing, cb, scope) {
3085             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3086         },
3087
3088         color : function(el, args, duration, easing, cb, scope) {
3089             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3090         },
3091
3092         run : function(el, args, duration, easing, cb, scope, type) {
3093             type = type || Roo.lib.AnimBase;
3094             if (typeof easing == "string") {
3095                 easing = Roo.lib.Easing[easing];
3096             }
3097             var anim = new type(el, args, duration, easing);
3098             anim.animateX(function() {
3099                 Roo.callback(cb, scope);
3100             });
3101             return anim;
3102         }
3103     };
3104 })();/*
3105  * Portions of this file are based on pieces of Yahoo User Interface Library
3106  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107  * YUI licensed under the BSD License:
3108  * http://developer.yahoo.net/yui/license.txt
3109  * <script type="text/javascript">
3110  *
3111  */
3112
3113 (function() {    
3114     var libFlyweight;
3115     
3116     function fly(el) {
3117         if (!libFlyweight) {
3118             libFlyweight = new Roo.Element.Flyweight();
3119         }
3120         libFlyweight.dom = el;
3121         return libFlyweight;
3122     }
3123
3124     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3125     
3126    
3127     
3128     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3129         if (el) {
3130             this.init(el, attributes, duration, method);
3131         }
3132     };
3133
3134     Roo.lib.AnimBase.fly = fly;
3135     
3136     
3137     
3138     Roo.lib.AnimBase.prototype = {
3139
3140         toString: function() {
3141             var el = this.getEl();
3142             var id = el.id || el.tagName;
3143             return ("Anim " + id);
3144         },
3145
3146         patterns: {
3147             noNegatives:        /width|height|opacity|padding/i,
3148             offsetAttribute:  /^((width|height)|(top|left))$/,
3149             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3150             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3151         },
3152
3153
3154         doMethod: function(attr, start, end) {
3155             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3156         },
3157
3158
3159         setAttribute: function(attr, val, unit) {
3160             if (this.patterns.noNegatives.test(attr)) {
3161                 val = (val > 0) ? val : 0;
3162             }
3163
3164             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3165         },
3166
3167
3168         getAttribute: function(attr) {
3169             var el = this.getEl();
3170             var val = fly(el).getStyle(attr);
3171
3172             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173                 return parseFloat(val);
3174             }
3175
3176             var a = this.patterns.offsetAttribute.exec(attr) || [];
3177             var pos = !!( a[3] );
3178             var box = !!( a[2] );
3179
3180
3181             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3183             } else {
3184                 val = 0;
3185             }
3186
3187             return val;
3188         },
3189
3190
3191         getDefaultUnit: function(attr) {
3192             if (this.patterns.defaultUnit.test(attr)) {
3193                 return 'px';
3194             }
3195
3196             return '';
3197         },
3198
3199         animateX : function(callback, scope) {
3200             var f = function() {
3201                 this.onComplete.removeListener(f);
3202                 if (typeof callback == "function") {
3203                     callback.call(scope || this, this);
3204                 }
3205             };
3206             this.onComplete.addListener(f, this);
3207             this.animate();
3208         },
3209
3210
3211         setRuntimeAttribute: function(attr) {
3212             var start;
3213             var end;
3214             var attributes = this.attributes;
3215
3216             this.runtimeAttributes[attr] = {};
3217
3218             var isset = function(prop) {
3219                 return (typeof prop !== 'undefined');
3220             };
3221
3222             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3223                 return false;
3224             }
3225
3226             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3227
3228
3229             if (isset(attributes[attr]['to'])) {
3230                 end = attributes[attr]['to'];
3231             } else if (isset(attributes[attr]['by'])) {
3232                 if (start.constructor == Array) {
3233                     end = [];
3234                     for (var i = 0, len = start.length; i < len; ++i) {
3235                         end[i] = start[i] + attributes[attr]['by'][i];
3236                     }
3237                 } else {
3238                     end = start + attributes[attr]['by'];
3239                 }
3240             }
3241
3242             this.runtimeAttributes[attr].start = start;
3243             this.runtimeAttributes[attr].end = end;
3244
3245
3246             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3247         },
3248
3249
3250         init: function(el, attributes, duration, method) {
3251
3252             var isAnimated = false;
3253
3254
3255             var startTime = null;
3256
3257
3258             var actualFrames = 0;
3259
3260
3261             el = Roo.getDom(el);
3262
3263
3264             this.attributes = attributes || {};
3265
3266
3267             this.duration = duration || 1;
3268
3269
3270             this.method = method || Roo.lib.Easing.easeNone;
3271
3272
3273             this.useSeconds = true;
3274
3275
3276             this.currentFrame = 0;
3277
3278
3279             this.totalFrames = Roo.lib.AnimMgr.fps;
3280
3281
3282             this.getEl = function() {
3283                 return el;
3284             };
3285
3286
3287             this.isAnimated = function() {
3288                 return isAnimated;
3289             };
3290
3291
3292             this.getStartTime = function() {
3293                 return startTime;
3294             };
3295
3296             this.runtimeAttributes = {};
3297
3298
3299             this.animate = function() {
3300                 if (this.isAnimated()) {
3301                     return false;
3302                 }
3303
3304                 this.currentFrame = 0;
3305
3306                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3307
3308                 Roo.lib.AnimMgr.registerElement(this);
3309             };
3310
3311
3312             this.stop = function(finish) {
3313                 if (finish) {
3314                     this.currentFrame = this.totalFrames;
3315                     this._onTween.fire();
3316                 }
3317                 Roo.lib.AnimMgr.stop(this);
3318             };
3319
3320             var onStart = function() {
3321                 this.onStart.fire();
3322
3323                 this.runtimeAttributes = {};
3324                 for (var attr in this.attributes) {
3325                     this.setRuntimeAttribute(attr);
3326                 }
3327
3328                 isAnimated = true;
3329                 actualFrames = 0;
3330                 startTime = new Date();
3331             };
3332
3333
3334             var onTween = function() {
3335                 var data = {
3336                     duration: new Date() - this.getStartTime(),
3337                     currentFrame: this.currentFrame
3338                 };
3339
3340                 data.toString = function() {
3341                     return (
3342                             'duration: ' + data.duration +
3343                             ', currentFrame: ' + data.currentFrame
3344                             );
3345                 };
3346
3347                 this.onTween.fire(data);
3348
3349                 var runtimeAttributes = this.runtimeAttributes;
3350
3351                 for (var attr in runtimeAttributes) {
3352                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3353                 }
3354
3355                 actualFrames += 1;
3356             };
3357
3358             var onComplete = function() {
3359                 var actual_duration = (new Date() - startTime) / 1000 ;
3360
3361                 var data = {
3362                     duration: actual_duration,
3363                     frames: actualFrames,
3364                     fps: actualFrames / actual_duration
3365                 };
3366
3367                 data.toString = function() {
3368                     return (
3369                             'duration: ' + data.duration +
3370                             ', frames: ' + data.frames +
3371                             ', fps: ' + data.fps
3372                             );
3373                 };
3374
3375                 isAnimated = false;
3376                 actualFrames = 0;
3377                 this.onComplete.fire(data);
3378             };
3379
3380
3381             this._onStart = new Roo.util.Event(this);
3382             this.onStart = new Roo.util.Event(this);
3383             this.onTween = new Roo.util.Event(this);
3384             this._onTween = new Roo.util.Event(this);
3385             this.onComplete = new Roo.util.Event(this);
3386             this._onComplete = new Roo.util.Event(this);
3387             this._onStart.addListener(onStart);
3388             this._onTween.addListener(onTween);
3389             this._onComplete.addListener(onComplete);
3390         }
3391     };
3392 })();
3393 /*
3394  * Portions of this file are based on pieces of Yahoo User Interface Library
3395  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396  * YUI licensed under the BSD License:
3397  * http://developer.yahoo.net/yui/license.txt
3398  * <script type="text/javascript">
3399  *
3400  */
3401
3402 Roo.lib.AnimMgr = new function() {
3403
3404         var thread = null;
3405
3406
3407         var queue = [];
3408
3409
3410         var tweenCount = 0;
3411
3412
3413         this.fps = 1000;
3414
3415
3416         this.delay = 1;
3417
3418
3419         this.registerElement = function(tween) {
3420             queue[queue.length] = tween;
3421             tweenCount += 1;
3422             tween._onStart.fire();
3423             this.start();
3424         };
3425
3426
3427         this.unRegister = function(tween, index) {
3428             tween._onComplete.fire();
3429             index = index || getIndex(tween);
3430             if (index != -1) {
3431                 queue.splice(index, 1);
3432             }
3433
3434             tweenCount -= 1;
3435             if (tweenCount <= 0) {
3436                 this.stop();
3437             }
3438         };
3439
3440
3441         this.start = function() {
3442             if (thread === null) {
3443                 thread = setInterval(this.run, this.delay);
3444             }
3445         };
3446
3447
3448         this.stop = function(tween) {
3449             if (!tween) {
3450                 clearInterval(thread);
3451
3452                 for (var i = 0, len = queue.length; i < len; ++i) {
3453                     if (queue[0].isAnimated()) {
3454                         this.unRegister(queue[0], 0);
3455                     }
3456                 }
3457
3458                 queue = [];
3459                 thread = null;
3460                 tweenCount = 0;
3461             }
3462             else {
3463                 this.unRegister(tween);
3464             }
3465         };
3466
3467
3468         this.run = function() {
3469             for (var i = 0, len = queue.length; i < len; ++i) {
3470                 var tween = queue[i];
3471                 if (!tween || !tween.isAnimated()) {
3472                     continue;
3473                 }
3474
3475                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3476                 {
3477                     tween.currentFrame += 1;
3478
3479                     if (tween.useSeconds) {
3480                         correctFrame(tween);
3481                     }
3482                     tween._onTween.fire();
3483                 }
3484                 else {
3485                     Roo.lib.AnimMgr.stop(tween, i);
3486                 }
3487             }
3488         };
3489
3490         var getIndex = function(anim) {
3491             for (var i = 0, len = queue.length; i < len; ++i) {
3492                 if (queue[i] == anim) {
3493                     return i;
3494                 }
3495             }
3496             return -1;
3497         };
3498
3499
3500         var correctFrame = function(tween) {
3501             var frames = tween.totalFrames;
3502             var frame = tween.currentFrame;
3503             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504             var elapsed = (new Date() - tween.getStartTime());
3505             var tweak = 0;
3506
3507             if (elapsed < tween.duration * 1000) {
3508                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3509             } else {
3510                 tweak = frames - (frame + 1);
3511             }
3512             if (tweak > 0 && isFinite(tweak)) {
3513                 if (tween.currentFrame + tweak >= frames) {
3514                     tweak = frames - (frame + 1);
3515                 }
3516
3517                 tween.currentFrame += tweak;
3518             }
3519         };
3520     };/*
3521  * Portions of this file are based on pieces of Yahoo User Interface Library
3522  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3523  * YUI licensed under the BSD License:
3524  * http://developer.yahoo.net/yui/license.txt
3525  * <script type="text/javascript">
3526  *
3527  */
3528 Roo.lib.Bezier = new function() {
3529
3530         this.getPosition = function(points, t) {
3531             var n = points.length;
3532             var tmp = [];
3533
3534             for (var i = 0; i < n; ++i) {
3535                 tmp[i] = [points[i][0], points[i][1]];
3536             }
3537
3538             for (var j = 1; j < n; ++j) {
3539                 for (i = 0; i < n - j; ++i) {
3540                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3541                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3542                 }
3543             }
3544
3545             return [ tmp[0][0], tmp[0][1] ];
3546
3547         };
3548     };/*
3549  * Portions of this file are based on pieces of Yahoo User Interface Library
3550  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3551  * YUI licensed under the BSD License:
3552  * http://developer.yahoo.net/yui/license.txt
3553  * <script type="text/javascript">
3554  *
3555  */
3556 (function() {
3557
3558     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3559         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3560     };
3561
3562     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3563
3564     var fly = Roo.lib.AnimBase.fly;
3565     var Y = Roo.lib;
3566     var superclass = Y.ColorAnim.superclass;
3567     var proto = Y.ColorAnim.prototype;
3568
3569     proto.toString = function() {
3570         var el = this.getEl();
3571         var id = el.id || el.tagName;
3572         return ("ColorAnim " + id);
3573     };
3574
3575     proto.patterns.color = /color$/i;
3576     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3577     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3578     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3579     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3580
3581
3582     proto.parseColor = function(s) {
3583         if (s.length == 3) {
3584             return s;
3585         }
3586
3587         var c = this.patterns.hex.exec(s);
3588         if (c && c.length == 4) {
3589             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3590         }
3591
3592         c = this.patterns.rgb.exec(s);
3593         if (c && c.length == 4) {
3594             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3595         }
3596
3597         c = this.patterns.hex3.exec(s);
3598         if (c && c.length == 4) {
3599             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3600         }
3601
3602         return null;
3603     };
3604     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3605     proto.getAttribute = function(attr) {
3606         var el = this.getEl();
3607         if (this.patterns.color.test(attr)) {
3608             var val = fly(el).getStyle(attr);
3609
3610             if (this.patterns.transparent.test(val)) {
3611                 var parent = el.parentNode;
3612                 val = fly(parent).getStyle(attr);
3613
3614                 while (parent && this.patterns.transparent.test(val)) {
3615                     parent = parent.parentNode;
3616                     val = fly(parent).getStyle(attr);
3617                     if (parent.tagName.toUpperCase() == 'HTML') {
3618                         val = '#fff';
3619                     }
3620                 }
3621             }
3622         } else {
3623             val = superclass.getAttribute.call(this, attr);
3624         }
3625
3626         return val;
3627     };
3628     proto.getAttribute = function(attr) {
3629         var el = this.getEl();
3630         if (this.patterns.color.test(attr)) {
3631             var val = fly(el).getStyle(attr);
3632
3633             if (this.patterns.transparent.test(val)) {
3634                 var parent = el.parentNode;
3635                 val = fly(parent).getStyle(attr);
3636
3637                 while (parent && this.patterns.transparent.test(val)) {
3638                     parent = parent.parentNode;
3639                     val = fly(parent).getStyle(attr);
3640                     if (parent.tagName.toUpperCase() == 'HTML') {
3641                         val = '#fff';
3642                     }
3643                 }
3644             }
3645         } else {
3646             val = superclass.getAttribute.call(this, attr);
3647         }
3648
3649         return val;
3650     };
3651
3652     proto.doMethod = function(attr, start, end) {
3653         var val;
3654
3655         if (this.patterns.color.test(attr)) {
3656             val = [];
3657             for (var i = 0, len = start.length; i < len; ++i) {
3658                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3659             }
3660
3661             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3662         }
3663         else {
3664             val = superclass.doMethod.call(this, attr, start, end);
3665         }
3666
3667         return val;
3668     };
3669
3670     proto.setRuntimeAttribute = function(attr) {
3671         superclass.setRuntimeAttribute.call(this, attr);
3672
3673         if (this.patterns.color.test(attr)) {
3674             var attributes = this.attributes;
3675             var start = this.parseColor(this.runtimeAttributes[attr].start);
3676             var end = this.parseColor(this.runtimeAttributes[attr].end);
3677
3678             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3679                 end = this.parseColor(attributes[attr].by);
3680
3681                 for (var i = 0, len = start.length; i < len; ++i) {
3682                     end[i] = start[i] + end[i];
3683                 }
3684             }
3685
3686             this.runtimeAttributes[attr].start = start;
3687             this.runtimeAttributes[attr].end = end;
3688         }
3689     };
3690 })();
3691
3692 /*
3693  * Portions of this file are based on pieces of Yahoo User Interface Library
3694  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3695  * YUI licensed under the BSD License:
3696  * http://developer.yahoo.net/yui/license.txt
3697  * <script type="text/javascript">
3698  *
3699  */
3700 Roo.lib.Easing = {
3701
3702
3703     easeNone: function (t, b, c, d) {
3704         return c * t / d + b;
3705     },
3706
3707
3708     easeIn: function (t, b, c, d) {
3709         return c * (t /= d) * t + b;
3710     },
3711
3712
3713     easeOut: function (t, b, c, d) {
3714         return -c * (t /= d) * (t - 2) + b;
3715     },
3716
3717
3718     easeBoth: function (t, b, c, d) {
3719         if ((t /= d / 2) < 1) {
3720             return c / 2 * t * t + b;
3721         }
3722
3723         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3724     },
3725
3726
3727     easeInStrong: function (t, b, c, d) {
3728         return c * (t /= d) * t * t * t + b;
3729     },
3730
3731
3732     easeOutStrong: function (t, b, c, d) {
3733         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3734     },
3735
3736
3737     easeBothStrong: function (t, b, c, d) {
3738         if ((t /= d / 2) < 1) {
3739             return c / 2 * t * t * t * t + b;
3740         }
3741
3742         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3743     },
3744
3745
3746
3747     elasticIn: function (t, b, c, d, a, p) {
3748         if (t == 0) {
3749             return b;
3750         }
3751         if ((t /= d) == 1) {
3752             return b + c;
3753         }
3754         if (!p) {
3755             p = d * .3;
3756         }
3757
3758         if (!a || a < Math.abs(c)) {
3759             a = c;
3760             var s = p / 4;
3761         }
3762         else {
3763             var s = p / (2 * Math.PI) * Math.asin(c / a);
3764         }
3765
3766         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3767     },
3768
3769
3770     elasticOut: function (t, b, c, d, a, p) {
3771         if (t == 0) {
3772             return b;
3773         }
3774         if ((t /= d) == 1) {
3775             return b + c;
3776         }
3777         if (!p) {
3778             p = d * .3;
3779         }
3780
3781         if (!a || a < Math.abs(c)) {
3782             a = c;
3783             var s = p / 4;
3784         }
3785         else {
3786             var s = p / (2 * Math.PI) * Math.asin(c / a);
3787         }
3788
3789         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3790     },
3791
3792
3793     elasticBoth: function (t, b, c, d, a, p) {
3794         if (t == 0) {
3795             return b;
3796         }
3797
3798         if ((t /= d / 2) == 2) {
3799             return b + c;
3800         }
3801
3802         if (!p) {
3803             p = d * (.3 * 1.5);
3804         }
3805
3806         if (!a || a < Math.abs(c)) {
3807             a = c;
3808             var s = p / 4;
3809         }
3810         else {
3811             var s = p / (2 * Math.PI) * Math.asin(c / a);
3812         }
3813
3814         if (t < 1) {
3815             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3816                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3817         }
3818         return a * Math.pow(2, -10 * (t -= 1)) *
3819                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3820     },
3821
3822
3823
3824     backIn: function (t, b, c, d, s) {
3825         if (typeof s == 'undefined') {
3826             s = 1.70158;
3827         }
3828         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3829     },
3830
3831
3832     backOut: function (t, b, c, d, s) {
3833         if (typeof s == 'undefined') {
3834             s = 1.70158;
3835         }
3836         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3837     },
3838
3839
3840     backBoth: function (t, b, c, d, s) {
3841         if (typeof s == 'undefined') {
3842             s = 1.70158;
3843         }
3844
3845         if ((t /= d / 2 ) < 1) {
3846             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3847         }
3848         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3849     },
3850
3851
3852     bounceIn: function (t, b, c, d) {
3853         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3854     },
3855
3856
3857     bounceOut: function (t, b, c, d) {
3858         if ((t /= d) < (1 / 2.75)) {
3859             return c * (7.5625 * t * t) + b;
3860         } else if (t < (2 / 2.75)) {
3861             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3862         } else if (t < (2.5 / 2.75)) {
3863             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3864         }
3865         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3866     },
3867
3868
3869     bounceBoth: function (t, b, c, d) {
3870         if (t < d / 2) {
3871             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3872         }
3873         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3874     }
3875 };/*
3876  * Portions of this file are based on pieces of Yahoo User Interface Library
3877  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3878  * YUI licensed under the BSD License:
3879  * http://developer.yahoo.net/yui/license.txt
3880  * <script type="text/javascript">
3881  *
3882  */
3883     (function() {
3884         Roo.lib.Motion = function(el, attributes, duration, method) {
3885             if (el) {
3886                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3887             }
3888         };
3889
3890         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3891
3892
3893         var Y = Roo.lib;
3894         var superclass = Y.Motion.superclass;
3895         var proto = Y.Motion.prototype;
3896
3897         proto.toString = function() {
3898             var el = this.getEl();
3899             var id = el.id || el.tagName;
3900             return ("Motion " + id);
3901         };
3902
3903         proto.patterns.points = /^points$/i;
3904
3905         proto.setAttribute = function(attr, val, unit) {
3906             if (this.patterns.points.test(attr)) {
3907                 unit = unit || 'px';
3908                 superclass.setAttribute.call(this, 'left', val[0], unit);
3909                 superclass.setAttribute.call(this, 'top', val[1], unit);
3910             } else {
3911                 superclass.setAttribute.call(this, attr, val, unit);
3912             }
3913         };
3914
3915         proto.getAttribute = function(attr) {
3916             if (this.patterns.points.test(attr)) {
3917                 var val = [
3918                         superclass.getAttribute.call(this, 'left'),
3919                         superclass.getAttribute.call(this, 'top')
3920                         ];
3921             } else {
3922                 val = superclass.getAttribute.call(this, attr);
3923             }
3924
3925             return val;
3926         };
3927
3928         proto.doMethod = function(attr, start, end) {
3929             var val = null;
3930
3931             if (this.patterns.points.test(attr)) {
3932                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3933                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3934             } else {
3935                 val = superclass.doMethod.call(this, attr, start, end);
3936             }
3937             return val;
3938         };
3939
3940         proto.setRuntimeAttribute = function(attr) {
3941             if (this.patterns.points.test(attr)) {
3942                 var el = this.getEl();
3943                 var attributes = this.attributes;
3944                 var start;
3945                 var control = attributes['points']['control'] || [];
3946                 var end;
3947                 var i, len;
3948
3949                 if (control.length > 0 && !(control[0] instanceof Array)) {
3950                     control = [control];
3951                 } else {
3952                     var tmp = [];
3953                     for (i = 0,len = control.length; i < len; ++i) {
3954                         tmp[i] = control[i];
3955                     }
3956                     control = tmp;
3957                 }
3958
3959                 Roo.fly(el).position();
3960
3961                 if (isset(attributes['points']['from'])) {
3962                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3963                 }
3964                 else {
3965                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3966                 }
3967
3968                 start = this.getAttribute('points');
3969
3970
3971                 if (isset(attributes['points']['to'])) {
3972                     end = translateValues.call(this, attributes['points']['to'], start);
3973
3974                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3975                     for (i = 0,len = control.length; i < len; ++i) {
3976                         control[i] = translateValues.call(this, control[i], start);
3977                     }
3978
3979
3980                 } else if (isset(attributes['points']['by'])) {
3981                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3982
3983                     for (i = 0,len = control.length; i < len; ++i) {
3984                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3985                     }
3986                 }
3987
3988                 this.runtimeAttributes[attr] = [start];
3989
3990                 if (control.length > 0) {
3991                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3992                 }
3993
3994                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3995             }
3996             else {
3997                 superclass.setRuntimeAttribute.call(this, attr);
3998             }
3999         };
4000
4001         var translateValues = function(val, start) {
4002             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4003             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4004
4005             return val;
4006         };
4007
4008         var isset = function(prop) {
4009             return (typeof prop !== 'undefined');
4010         };
4011     })();
4012 /*
4013  * Portions of this file are based on pieces of Yahoo User Interface Library
4014  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4015  * YUI licensed under the BSD License:
4016  * http://developer.yahoo.net/yui/license.txt
4017  * <script type="text/javascript">
4018  *
4019  */
4020     (function() {
4021         Roo.lib.Scroll = function(el, attributes, duration, method) {
4022             if (el) {
4023                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4024             }
4025         };
4026
4027         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4028
4029
4030         var Y = Roo.lib;
4031         var superclass = Y.Scroll.superclass;
4032         var proto = Y.Scroll.prototype;
4033
4034         proto.toString = function() {
4035             var el = this.getEl();
4036             var id = el.id || el.tagName;
4037             return ("Scroll " + id);
4038         };
4039
4040         proto.doMethod = function(attr, start, end) {
4041             var val = null;
4042
4043             if (attr == 'scroll') {
4044                 val = [
4045                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4046                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4047                         ];
4048
4049             } else {
4050                 val = superclass.doMethod.call(this, attr, start, end);
4051             }
4052             return val;
4053         };
4054
4055         proto.getAttribute = function(attr) {
4056             var val = null;
4057             var el = this.getEl();
4058
4059             if (attr == 'scroll') {
4060                 val = [ el.scrollLeft, el.scrollTop ];
4061             } else {
4062                 val = superclass.getAttribute.call(this, attr);
4063             }
4064
4065             return val;
4066         };
4067
4068         proto.setAttribute = function(attr, val, unit) {
4069             var el = this.getEl();
4070
4071             if (attr == 'scroll') {
4072                 el.scrollLeft = val[0];
4073                 el.scrollTop = val[1];
4074             } else {
4075                 superclass.setAttribute.call(this, attr, val, unit);
4076             }
4077         };
4078     })();
4079 /*
4080  * Based on:
4081  * Ext JS Library 1.1.1
4082  * Copyright(c) 2006-2007, Ext JS, LLC.
4083  *
4084  * Originally Released Under LGPL - original licence link has changed is not relivant.
4085  *
4086  * Fork - LGPL
4087  * <script type="text/javascript">
4088  */
4089
4090
4091 // nasty IE9 hack - what a pile of crap that is..
4092
4093  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4094     Range.prototype.createContextualFragment = function (html) {
4095         var doc = window.document;
4096         var container = doc.createElement("div");
4097         container.innerHTML = html;
4098         var frag = doc.createDocumentFragment(), n;
4099         while ((n = container.firstChild)) {
4100             frag.appendChild(n);
4101         }
4102         return frag;
4103     };
4104 }
4105
4106 /**
4107  * @class Roo.DomHelper
4108  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4109  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4110  * @singleton
4111  */
4112 Roo.DomHelper = function(){
4113     var tempTableEl = null;
4114     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4115     var tableRe = /^table|tbody|tr|td$/i;
4116     var xmlns = {};
4117     // build as innerHTML where available
4118     /** @ignore */
4119     var createHtml = function(o){
4120         if(typeof o == 'string'){
4121             return o;
4122         }
4123         var b = "";
4124         if(!o.tag){
4125             o.tag = "div";
4126         }
4127         b += "<" + o.tag;
4128         for(var attr in o){
4129             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4130             if(attr == "style"){
4131                 var s = o["style"];
4132                 if(typeof s == "function"){
4133                     s = s.call();
4134                 }
4135                 if(typeof s == "string"){
4136                     b += ' style="' + s + '"';
4137                 }else if(typeof s == "object"){
4138                     b += ' style="';
4139                     for(var key in s){
4140                         if(typeof s[key] != "function"){
4141                             b += key + ":" + s[key] + ";";
4142                         }
4143                     }
4144                     b += '"';
4145                 }
4146             }else{
4147                 if(attr == "cls"){
4148                     b += ' class="' + o["cls"] + '"';
4149                 }else if(attr == "htmlFor"){
4150                     b += ' for="' + o["htmlFor"] + '"';
4151                 }else{
4152                     b += " " + attr + '="' + o[attr] + '"';
4153                 }
4154             }
4155         }
4156         if(emptyTags.test(o.tag)){
4157             b += "/>";
4158         }else{
4159             b += ">";
4160             var cn = o.children || o.cn;
4161             if(cn){
4162                 //http://bugs.kde.org/show_bug.cgi?id=71506
4163                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4164                     for(var i = 0, len = cn.length; i < len; i++) {
4165                         b += createHtml(cn[i], b);
4166                     }
4167                 }else{
4168                     b += createHtml(cn, b);
4169                 }
4170             }
4171             if(o.html){
4172                 b += o.html;
4173             }
4174             b += "</" + o.tag + ">";
4175         }
4176         return b;
4177     };
4178
4179     // build as dom
4180     /** @ignore */
4181     var createDom = function(o, parentNode){
4182          
4183         // defininition craeted..
4184         var ns = false;
4185         if (o.ns && o.ns != 'html') {
4186                
4187             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4188                 xmlns[o.ns] = o.xmlns;
4189                 ns = o.xmlns;
4190             }
4191             if (typeof(xmlns[o.ns]) == 'undefined') {
4192                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4193             }
4194             ns = xmlns[o.ns];
4195         }
4196         
4197         
4198         if (typeof(o) == 'string') {
4199             return parentNode.appendChild(document.createTextNode(o));
4200         }
4201         o.tag = o.tag || div;
4202         if (o.ns && Roo.isIE) {
4203             ns = false;
4204             o.tag = o.ns + ':' + o.tag;
4205             
4206         }
4207         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4208         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4209         for(var attr in o){
4210             
4211             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4212                     attr == "style" || typeof o[attr] == "function") continue;
4213                     
4214             if(attr=="cls" && Roo.isIE){
4215                 el.className = o["cls"];
4216             }else{
4217                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4218                 else el[attr] = o[attr];
4219             }
4220         }
4221         Roo.DomHelper.applyStyles(el, o.style);
4222         var cn = o.children || o.cn;
4223         if(cn){
4224             //http://bugs.kde.org/show_bug.cgi?id=71506
4225              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4226                 for(var i = 0, len = cn.length; i < len; i++) {
4227                     createDom(cn[i], el);
4228                 }
4229             }else{
4230                 createDom(cn, el);
4231             }
4232         }
4233         if(o.html){
4234             el.innerHTML = o.html;
4235         }
4236         if(parentNode){
4237            parentNode.appendChild(el);
4238         }
4239         return el;
4240     };
4241
4242     var ieTable = function(depth, s, h, e){
4243         tempTableEl.innerHTML = [s, h, e].join('');
4244         var i = -1, el = tempTableEl;
4245         while(++i < depth){
4246             el = el.firstChild;
4247         }
4248         return el;
4249     };
4250
4251     // kill repeat to save bytes
4252     var ts = '<table>',
4253         te = '</table>',
4254         tbs = ts+'<tbody>',
4255         tbe = '</tbody>'+te,
4256         trs = tbs + '<tr>',
4257         tre = '</tr>'+tbe;
4258
4259     /**
4260      * @ignore
4261      * Nasty code for IE's broken table implementation
4262      */
4263     var insertIntoTable = function(tag, where, el, html){
4264         if(!tempTableEl){
4265             tempTableEl = document.createElement('div');
4266         }
4267         var node;
4268         var before = null;
4269         if(tag == 'td'){
4270             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4271                 return;
4272             }
4273             if(where == 'beforebegin'){
4274                 before = el;
4275                 el = el.parentNode;
4276             } else{
4277                 before = el.nextSibling;
4278                 el = el.parentNode;
4279             }
4280             node = ieTable(4, trs, html, tre);
4281         }
4282         else if(tag == 'tr'){
4283             if(where == 'beforebegin'){
4284                 before = el;
4285                 el = el.parentNode;
4286                 node = ieTable(3, tbs, html, tbe);
4287             } else if(where == 'afterend'){
4288                 before = el.nextSibling;
4289                 el = el.parentNode;
4290                 node = ieTable(3, tbs, html, tbe);
4291             } else{ // INTO a TR
4292                 if(where == 'afterbegin'){
4293                     before = el.firstChild;
4294                 }
4295                 node = ieTable(4, trs, html, tre);
4296             }
4297         } else if(tag == 'tbody'){
4298             if(where == 'beforebegin'){
4299                 before = el;
4300                 el = el.parentNode;
4301                 node = ieTable(2, ts, html, te);
4302             } else if(where == 'afterend'){
4303                 before = el.nextSibling;
4304                 el = el.parentNode;
4305                 node = ieTable(2, ts, html, te);
4306             } else{
4307                 if(where == 'afterbegin'){
4308                     before = el.firstChild;
4309                 }
4310                 node = ieTable(3, tbs, html, tbe);
4311             }
4312         } else{ // TABLE
4313             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4314                 return;
4315             }
4316             if(where == 'afterbegin'){
4317                 before = el.firstChild;
4318             }
4319             node = ieTable(2, ts, html, te);
4320         }
4321         el.insertBefore(node, before);
4322         return node;
4323     };
4324
4325     return {
4326     /** True to force the use of DOM instead of html fragments @type Boolean */
4327     useDom : false,
4328
4329     /**
4330      * Returns the markup for the passed Element(s) config
4331      * @param {Object} o The Dom object spec (and children)
4332      * @return {String}
4333      */
4334     markup : function(o){
4335         return createHtml(o);
4336     },
4337
4338     /**
4339      * Applies a style specification to an element
4340      * @param {String/HTMLElement} el The element to apply styles to
4341      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4342      * a function which returns such a specification.
4343      */
4344     applyStyles : function(el, styles){
4345         if(styles){
4346            el = Roo.fly(el);
4347            if(typeof styles == "string"){
4348                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4349                var matches;
4350                while ((matches = re.exec(styles)) != null){
4351                    el.setStyle(matches[1], matches[2]);
4352                }
4353            }else if (typeof styles == "object"){
4354                for (var style in styles){
4355                   el.setStyle(style, styles[style]);
4356                }
4357            }else if (typeof styles == "function"){
4358                 Roo.DomHelper.applyStyles(el, styles.call());
4359            }
4360         }
4361     },
4362
4363     /**
4364      * Inserts an HTML fragment into the Dom
4365      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4366      * @param {HTMLElement} el The context element
4367      * @param {String} html The HTML fragmenet
4368      * @return {HTMLElement} The new node
4369      */
4370     insertHtml : function(where, el, html){
4371         where = where.toLowerCase();
4372         if(el.insertAdjacentHTML){
4373             if(tableRe.test(el.tagName)){
4374                 var rs;
4375                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4376                     return rs;
4377                 }
4378             }
4379             switch(where){
4380                 case "beforebegin":
4381                     el.insertAdjacentHTML('BeforeBegin', html);
4382                     return el.previousSibling;
4383                 case "afterbegin":
4384                     el.insertAdjacentHTML('AfterBegin', html);
4385                     return el.firstChild;
4386                 case "beforeend":
4387                     el.insertAdjacentHTML('BeforeEnd', html);
4388                     return el.lastChild;
4389                 case "afterend":
4390                     el.insertAdjacentHTML('AfterEnd', html);
4391                     return el.nextSibling;
4392             }
4393             throw 'Illegal insertion point -> "' + where + '"';
4394         }
4395         var range = el.ownerDocument.createRange();
4396         var frag;
4397         switch(where){
4398              case "beforebegin":
4399                 range.setStartBefore(el);
4400                 frag = range.createContextualFragment(html);
4401                 el.parentNode.insertBefore(frag, el);
4402                 return el.previousSibling;
4403              case "afterbegin":
4404                 if(el.firstChild){
4405                     range.setStartBefore(el.firstChild);
4406                     frag = range.createContextualFragment(html);
4407                     el.insertBefore(frag, el.firstChild);
4408                     return el.firstChild;
4409                 }else{
4410                     el.innerHTML = html;
4411                     return el.firstChild;
4412                 }
4413             case "beforeend":
4414                 if(el.lastChild){
4415                     range.setStartAfter(el.lastChild);
4416                     frag = range.createContextualFragment(html);
4417                     el.appendChild(frag);
4418                     return el.lastChild;
4419                 }else{
4420                     el.innerHTML = html;
4421                     return el.lastChild;
4422                 }
4423             case "afterend":
4424                 range.setStartAfter(el);
4425                 frag = range.createContextualFragment(html);
4426                 el.parentNode.insertBefore(frag, el.nextSibling);
4427                 return el.nextSibling;
4428             }
4429             throw 'Illegal insertion point -> "' + where + '"';
4430     },
4431
4432     /**
4433      * Creates new Dom element(s) and inserts them before el
4434      * @param {String/HTMLElement/Element} el The context element
4435      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4436      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4437      * @return {HTMLElement/Roo.Element} The new node
4438      */
4439     insertBefore : function(el, o, returnElement){
4440         return this.doInsert(el, o, returnElement, "beforeBegin");
4441     },
4442
4443     /**
4444      * Creates new Dom element(s) and inserts them after el
4445      * @param {String/HTMLElement/Element} el The context element
4446      * @param {Object} o The Dom object spec (and children)
4447      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4448      * @return {HTMLElement/Roo.Element} The new node
4449      */
4450     insertAfter : function(el, o, returnElement){
4451         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4452     },
4453
4454     /**
4455      * Creates new Dom element(s) and inserts them as the first child of el
4456      * @param {String/HTMLElement/Element} el The context element
4457      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4458      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4459      * @return {HTMLElement/Roo.Element} The new node
4460      */
4461     insertFirst : function(el, o, returnElement){
4462         return this.doInsert(el, o, returnElement, "afterBegin");
4463     },
4464
4465     // private
4466     doInsert : function(el, o, returnElement, pos, sibling){
4467         el = Roo.getDom(el);
4468         var newNode;
4469         if(this.useDom || o.ns){
4470             newNode = createDom(o, null);
4471             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4472         }else{
4473             var html = createHtml(o);
4474             newNode = this.insertHtml(pos, el, html);
4475         }
4476         return returnElement ? Roo.get(newNode, true) : newNode;
4477     },
4478
4479     /**
4480      * Creates new Dom element(s) and appends them to el
4481      * @param {String/HTMLElement/Element} el The context element
4482      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4483      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484      * @return {HTMLElement/Roo.Element} The new node
4485      */
4486     append : function(el, o, returnElement){
4487         el = Roo.getDom(el);
4488         var newNode;
4489         if(this.useDom || o.ns){
4490             newNode = createDom(o, null);
4491             el.appendChild(newNode);
4492         }else{
4493             var html = createHtml(o);
4494             newNode = this.insertHtml("beforeEnd", el, html);
4495         }
4496         return returnElement ? Roo.get(newNode, true) : newNode;
4497     },
4498
4499     /**
4500      * Creates new Dom element(s) and overwrites the contents of el with them
4501      * @param {String/HTMLElement/Element} el The context element
4502      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4503      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4504      * @return {HTMLElement/Roo.Element} The new node
4505      */
4506     overwrite : function(el, o, returnElement){
4507         el = Roo.getDom(el);
4508         if (o.ns) {
4509           
4510             while (el.childNodes.length) {
4511                 el.removeChild(el.firstChild);
4512             }
4513             createDom(o, el);
4514         } else {
4515             el.innerHTML = createHtml(o);   
4516         }
4517         
4518         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4519     },
4520
4521     /**
4522      * Creates a new Roo.DomHelper.Template from the Dom object spec
4523      * @param {Object} o The Dom object spec (and children)
4524      * @return {Roo.DomHelper.Template} The new template
4525      */
4526     createTemplate : function(o){
4527         var html = createHtml(o);
4528         return new Roo.Template(html);
4529     }
4530     };
4531 }();
4532 /*
4533  * Based on:
4534  * Ext JS Library 1.1.1
4535  * Copyright(c) 2006-2007, Ext JS, LLC.
4536  *
4537  * Originally Released Under LGPL - original licence link has changed is not relivant.
4538  *
4539  * Fork - LGPL
4540  * <script type="text/javascript">
4541  */
4542  
4543 /**
4544 * @class Roo.Template
4545 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4546 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4547 * Usage:
4548 <pre><code>
4549 var t = new Roo.Template({
4550     html :  '&lt;div name="{id}"&gt;' + 
4551         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4552         '&lt;/div&gt;',
4553     myformat: function (value, allValues) {
4554         return 'XX' + value;
4555     }
4556 });
4557 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4558 </code></pre>
4559 * For more information see this blog post with examples:
4560 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4561      - Create Elements using DOM, HTML fragments and Templates</a>. 
4562 * @constructor
4563 * @param {Object} cfg - Configuration object.
4564 */
4565 Roo.Template = function(cfg){
4566     // BC!
4567     if(cfg instanceof Array){
4568         cfg = cfg.join("");
4569     }else if(arguments.length > 1){
4570         cfg = Array.prototype.join.call(arguments, "");
4571     }
4572     
4573     
4574     if (typeof(cfg) == 'object') {
4575         Roo.apply(this,cfg)
4576     } else {
4577         // bc
4578         this.html = cfg;
4579     }
4580     if (this.url) {
4581         this.load();
4582     }
4583     
4584 };
4585 Roo.Template.prototype = {
4586     
4587     /**
4588      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4589      *                    it should be fixed so that template is observable...
4590      */
4591     url : false,
4592     /**
4593      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4594      */
4595     html : '',
4596     /**
4597      * Returns an HTML fragment of this template with the specified values applied.
4598      * @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'})
4599      * @return {String} The HTML fragment
4600      */
4601     applyTemplate : function(values){
4602         try {
4603            
4604             if(this.compiled){
4605                 return this.compiled(values);
4606             }
4607             var useF = this.disableFormats !== true;
4608             var fm = Roo.util.Format, tpl = this;
4609             var fn = function(m, name, format, args){
4610                 if(format && useF){
4611                     if(format.substr(0, 5) == "this."){
4612                         return tpl.call(format.substr(5), values[name], values);
4613                     }else{
4614                         if(args){
4615                             // quoted values are required for strings in compiled templates, 
4616                             // but for non compiled we need to strip them
4617                             // quoted reversed for jsmin
4618                             var re = /^\s*['"](.*)["']\s*$/;
4619                             args = args.split(',');
4620                             for(var i = 0, len = args.length; i < len; i++){
4621                                 args[i] = args[i].replace(re, "$1");
4622                             }
4623                             args = [values[name]].concat(args);
4624                         }else{
4625                             args = [values[name]];
4626                         }
4627                         return fm[format].apply(fm, args);
4628                     }
4629                 }else{
4630                     return values[name] !== undefined ? values[name] : "";
4631                 }
4632             };
4633             return this.html.replace(this.re, fn);
4634         } catch (e) {
4635             Roo.log(e);
4636             throw e;
4637         }
4638          
4639     },
4640     
4641     loading : false,
4642       
4643     load : function ()
4644     {
4645          
4646         if (this.loading) {
4647             return;
4648         }
4649         var _t = this;
4650         
4651         this.loading = true;
4652         this.compiled = false;
4653         
4654         var cx = new Roo.data.Connection();
4655         cx.request({
4656             url : this.url,
4657             method : 'GET',
4658             success : function (response) {
4659                 _t.loading = false;
4660                 _t.html = response.responseText;
4661                 _t.url = false;
4662                 _t.compile();
4663              },
4664             failure : function(response) {
4665                 Roo.log("Template failed to load from " + _t.url);
4666                 _t.loading = false;
4667             }
4668         });
4669     },
4670
4671     /**
4672      * Sets the HTML used as the template and optionally compiles it.
4673      * @param {String} html
4674      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4675      * @return {Roo.Template} this
4676      */
4677     set : function(html, compile){
4678         this.html = html;
4679         this.compiled = null;
4680         if(compile){
4681             this.compile();
4682         }
4683         return this;
4684     },
4685     
4686     /**
4687      * True to disable format functions (defaults to false)
4688      * @type Boolean
4689      */
4690     disableFormats : false,
4691     
4692     /**
4693     * The regular expression used to match template variables 
4694     * @type RegExp
4695     * @property 
4696     */
4697     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4698     
4699     /**
4700      * Compiles the template into an internal function, eliminating the RegEx overhead.
4701      * @return {Roo.Template} this
4702      */
4703     compile : function(){
4704         var fm = Roo.util.Format;
4705         var useF = this.disableFormats !== true;
4706         var sep = Roo.isGecko ? "+" : ",";
4707         var fn = function(m, name, format, args){
4708             if(format && useF){
4709                 args = args ? ',' + args : "";
4710                 if(format.substr(0, 5) != "this."){
4711                     format = "fm." + format + '(';
4712                 }else{
4713                     format = 'this.call("'+ format.substr(5) + '", ';
4714                     args = ", values";
4715                 }
4716             }else{
4717                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4718             }
4719             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4720         };
4721         var body;
4722         // branched to use + in gecko and [].join() in others
4723         if(Roo.isGecko){
4724             body = "this.compiled = function(values){ return '" +
4725                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4726                     "';};";
4727         }else{
4728             body = ["this.compiled = function(values){ return ['"];
4729             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4730             body.push("'].join('');};");
4731             body = body.join('');
4732         }
4733         /**
4734          * eval:var:values
4735          * eval:var:fm
4736          */
4737         eval(body);
4738         return this;
4739     },
4740     
4741     // private function used to call members
4742     call : function(fnName, value, allValues){
4743         return this[fnName](value, allValues);
4744     },
4745     
4746     /**
4747      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4748      * @param {String/HTMLElement/Roo.Element} el The context element
4749      * @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'})
4750      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4751      * @return {HTMLElement/Roo.Element} The new node or Element
4752      */
4753     insertFirst: function(el, values, returnElement){
4754         return this.doInsert('afterBegin', el, values, returnElement);
4755     },
4756
4757     /**
4758      * Applies the supplied values to the template and inserts the new node(s) before el.
4759      * @param {String/HTMLElement/Roo.Element} el The context element
4760      * @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'})
4761      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4762      * @return {HTMLElement/Roo.Element} The new node or Element
4763      */
4764     insertBefore: function(el, values, returnElement){
4765         return this.doInsert('beforeBegin', el, values, returnElement);
4766     },
4767
4768     /**
4769      * Applies the supplied values to the template and inserts the new node(s) after el.
4770      * @param {String/HTMLElement/Roo.Element} el The context element
4771      * @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'})
4772      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4773      * @return {HTMLElement/Roo.Element} The new node or Element
4774      */
4775     insertAfter : function(el, values, returnElement){
4776         return this.doInsert('afterEnd', el, values, returnElement);
4777     },
4778     
4779     /**
4780      * Applies the supplied values to the template and appends the new node(s) to el.
4781      * @param {String/HTMLElement/Roo.Element} el The context element
4782      * @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'})
4783      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4784      * @return {HTMLElement/Roo.Element} The new node or Element
4785      */
4786     append : function(el, values, returnElement){
4787         return this.doInsert('beforeEnd', el, values, returnElement);
4788     },
4789
4790     doInsert : function(where, el, values, returnEl){
4791         el = Roo.getDom(el);
4792         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4793         return returnEl ? Roo.get(newNode, true) : newNode;
4794     },
4795
4796     /**
4797      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4798      * @param {String/HTMLElement/Roo.Element} el The context element
4799      * @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'})
4800      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4801      * @return {HTMLElement/Roo.Element} The new node or Element
4802      */
4803     overwrite : function(el, values, returnElement){
4804         el = Roo.getDom(el);
4805         el.innerHTML = this.applyTemplate(values);
4806         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4807     }
4808 };
4809 /**
4810  * Alias for {@link #applyTemplate}
4811  * @method
4812  */
4813 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4814
4815 // backwards compat
4816 Roo.DomHelper.Template = Roo.Template;
4817
4818 /**
4819  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4820  * @param {String/HTMLElement} el A DOM element or its id
4821  * @returns {Roo.Template} The created template
4822  * @static
4823  */
4824 Roo.Template.from = function(el){
4825     el = Roo.getDom(el);
4826     return new Roo.Template(el.value || el.innerHTML);
4827 };/*
4828  * Based on:
4829  * Ext JS Library 1.1.1
4830  * Copyright(c) 2006-2007, Ext JS, LLC.
4831  *
4832  * Originally Released Under LGPL - original licence link has changed is not relivant.
4833  *
4834  * Fork - LGPL
4835  * <script type="text/javascript">
4836  */
4837  
4838
4839 /*
4840  * This is code is also distributed under MIT license for use
4841  * with jQuery and prototype JavaScript libraries.
4842  */
4843 /**
4844  * @class Roo.DomQuery
4845 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).
4846 <p>
4847 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>
4848
4849 <p>
4850 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.
4851 </p>
4852 <h4>Element Selectors:</h4>
4853 <ul class="list">
4854     <li> <b>*</b> any element</li>
4855     <li> <b>E</b> an element with the tag E</li>
4856     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4857     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4858     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4859     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4860 </ul>
4861 <h4>Attribute Selectors:</h4>
4862 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4863 <ul class="list">
4864     <li> <b>E[foo]</b> has an attribute "foo"</li>
4865     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4866     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4867     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4868     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4869     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4870     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4871 </ul>
4872 <h4>Pseudo Classes:</h4>
4873 <ul class="list">
4874     <li> <b>E:first-child</b> E is the first child of its parent</li>
4875     <li> <b>E:last-child</b> E is the last child of its parent</li>
4876     <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>
4877     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4878     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4879     <li> <b>E:only-child</b> E is the only child of its parent</li>
4880     <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>
4881     <li> <b>E:first</b> the first E in the resultset</li>
4882     <li> <b>E:last</b> the last E in the resultset</li>
4883     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4884     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4885     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4886     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4887     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4888     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4889     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4890     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4891     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4892 </ul>
4893 <h4>CSS Value Selectors:</h4>
4894 <ul class="list">
4895     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4896     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4897     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4898     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4899     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4900     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4901 </ul>
4902  * @singleton
4903  */
4904 Roo.DomQuery = function(){
4905     var cache = {}, simpleCache = {}, valueCache = {};
4906     var nonSpace = /\S/;
4907     var trimRe = /^\s+|\s+$/g;
4908     var tplRe = /\{(\d+)\}/g;
4909     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4910     var tagTokenRe = /^(#)?([\w-\*]+)/;
4911     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4912
4913     function child(p, index){
4914         var i = 0;
4915         var n = p.firstChild;
4916         while(n){
4917             if(n.nodeType == 1){
4918                if(++i == index){
4919                    return n;
4920                }
4921             }
4922             n = n.nextSibling;
4923         }
4924         return null;
4925     };
4926
4927     function next(n){
4928         while((n = n.nextSibling) && n.nodeType != 1);
4929         return n;
4930     };
4931
4932     function prev(n){
4933         while((n = n.previousSibling) && n.nodeType != 1);
4934         return n;
4935     };
4936
4937     function children(d){
4938         var n = d.firstChild, ni = -1;
4939             while(n){
4940                 var nx = n.nextSibling;
4941                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4942                     d.removeChild(n);
4943                 }else{
4944                     n.nodeIndex = ++ni;
4945                 }
4946                 n = nx;
4947             }
4948             return this;
4949         };
4950
4951     function byClassName(c, a, v){
4952         if(!v){
4953             return c;
4954         }
4955         var r = [], ri = -1, cn;
4956         for(var i = 0, ci; ci = c[i]; i++){
4957             if((' '+ci.className+' ').indexOf(v) != -1){
4958                 r[++ri] = ci;
4959             }
4960         }
4961         return r;
4962     };
4963
4964     function attrValue(n, attr){
4965         if(!n.tagName && typeof n.length != "undefined"){
4966             n = n[0];
4967         }
4968         if(!n){
4969             return null;
4970         }
4971         if(attr == "for"){
4972             return n.htmlFor;
4973         }
4974         if(attr == "class" || attr == "className"){
4975             return n.className;
4976         }
4977         return n.getAttribute(attr) || n[attr];
4978
4979     };
4980
4981     function getNodes(ns, mode, tagName){
4982         var result = [], ri = -1, cs;
4983         if(!ns){
4984             return result;
4985         }
4986         tagName = tagName || "*";
4987         if(typeof ns.getElementsByTagName != "undefined"){
4988             ns = [ns];
4989         }
4990         if(!mode){
4991             for(var i = 0, ni; ni = ns[i]; i++){
4992                 cs = ni.getElementsByTagName(tagName);
4993                 for(var j = 0, ci; ci = cs[j]; j++){
4994                     result[++ri] = ci;
4995                 }
4996             }
4997         }else if(mode == "/" || mode == ">"){
4998             var utag = tagName.toUpperCase();
4999             for(var i = 0, ni, cn; ni = ns[i]; i++){
5000                 cn = ni.children || ni.childNodes;
5001                 for(var j = 0, cj; cj = cn[j]; j++){
5002                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5003                         result[++ri] = cj;
5004                     }
5005                 }
5006             }
5007         }else if(mode == "+"){
5008             var utag = tagName.toUpperCase();
5009             for(var i = 0, n; n = ns[i]; i++){
5010                 while((n = n.nextSibling) && n.nodeType != 1);
5011                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5012                     result[++ri] = n;
5013                 }
5014             }
5015         }else if(mode == "~"){
5016             for(var i = 0, n; n = ns[i]; i++){
5017                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5018                 if(n){
5019                     result[++ri] = n;
5020                 }
5021             }
5022         }
5023         return result;
5024     };
5025
5026     function concat(a, b){
5027         if(b.slice){
5028             return a.concat(b);
5029         }
5030         for(var i = 0, l = b.length; i < l; i++){
5031             a[a.length] = b[i];
5032         }
5033         return a;
5034     }
5035
5036     function byTag(cs, tagName){
5037         if(cs.tagName || cs == document){
5038             cs = [cs];
5039         }
5040         if(!tagName){
5041             return cs;
5042         }
5043         var r = [], ri = -1;
5044         tagName = tagName.toLowerCase();
5045         for(var i = 0, ci; ci = cs[i]; i++){
5046             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5047                 r[++ri] = ci;
5048             }
5049         }
5050         return r;
5051     };
5052
5053     function byId(cs, attr, id){
5054         if(cs.tagName || cs == document){
5055             cs = [cs];
5056         }
5057         if(!id){
5058             return cs;
5059         }
5060         var r = [], ri = -1;
5061         for(var i = 0,ci; ci = cs[i]; i++){
5062             if(ci && ci.id == id){
5063                 r[++ri] = ci;
5064                 return r;
5065             }
5066         }
5067         return r;
5068     };
5069
5070     function byAttribute(cs, attr, value, op, custom){
5071         var r = [], ri = -1, st = custom=="{";
5072         var f = Roo.DomQuery.operators[op];
5073         for(var i = 0, ci; ci = cs[i]; i++){
5074             var a;
5075             if(st){
5076                 a = Roo.DomQuery.getStyle(ci, attr);
5077             }
5078             else if(attr == "class" || attr == "className"){
5079                 a = ci.className;
5080             }else if(attr == "for"){
5081                 a = ci.htmlFor;
5082             }else if(attr == "href"){
5083                 a = ci.getAttribute("href", 2);
5084             }else{
5085                 a = ci.getAttribute(attr);
5086             }
5087             if((f && f(a, value)) || (!f && a)){
5088                 r[++ri] = ci;
5089             }
5090         }
5091         return r;
5092     };
5093
5094     function byPseudo(cs, name, value){
5095         return Roo.DomQuery.pseudos[name](cs, value);
5096     };
5097
5098     // This is for IE MSXML which does not support expandos.
5099     // IE runs the same speed using setAttribute, however FF slows way down
5100     // and Safari completely fails so they need to continue to use expandos.
5101     var isIE = window.ActiveXObject ? true : false;
5102
5103     // this eval is stop the compressor from
5104     // renaming the variable to something shorter
5105     
5106     /** eval:var:batch */
5107     var batch = 30803; 
5108
5109     var key = 30803;
5110
5111     function nodupIEXml(cs){
5112         var d = ++key;
5113         cs[0].setAttribute("_nodup", d);
5114         var r = [cs[0]];
5115         for(var i = 1, len = cs.length; i < len; i++){
5116             var c = cs[i];
5117             if(!c.getAttribute("_nodup") != d){
5118                 c.setAttribute("_nodup", d);
5119                 r[r.length] = c;
5120             }
5121         }
5122         for(var i = 0, len = cs.length; i < len; i++){
5123             cs[i].removeAttribute("_nodup");
5124         }
5125         return r;
5126     }
5127
5128     function nodup(cs){
5129         if(!cs){
5130             return [];
5131         }
5132         var len = cs.length, c, i, r = cs, cj, ri = -1;
5133         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5134             return cs;
5135         }
5136         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5137             return nodupIEXml(cs);
5138         }
5139         var d = ++key;
5140         cs[0]._nodup = d;
5141         for(i = 1; c = cs[i]; i++){
5142             if(c._nodup != d){
5143                 c._nodup = d;
5144             }else{
5145                 r = [];
5146                 for(var j = 0; j < i; j++){
5147                     r[++ri] = cs[j];
5148                 }
5149                 for(j = i+1; cj = cs[j]; j++){
5150                     if(cj._nodup != d){
5151                         cj._nodup = d;
5152                         r[++ri] = cj;
5153                     }
5154                 }
5155                 return r;
5156             }
5157         }
5158         return r;
5159     }
5160
5161     function quickDiffIEXml(c1, c2){
5162         var d = ++key;
5163         for(var i = 0, len = c1.length; i < len; i++){
5164             c1[i].setAttribute("_qdiff", d);
5165         }
5166         var r = [];
5167         for(var i = 0, len = c2.length; i < len; i++){
5168             if(c2[i].getAttribute("_qdiff") != d){
5169                 r[r.length] = c2[i];
5170             }
5171         }
5172         for(var i = 0, len = c1.length; i < len; i++){
5173            c1[i].removeAttribute("_qdiff");
5174         }
5175         return r;
5176     }
5177
5178     function quickDiff(c1, c2){
5179         var len1 = c1.length;
5180         if(!len1){
5181             return c2;
5182         }
5183         if(isIE && c1[0].selectSingleNode){
5184             return quickDiffIEXml(c1, c2);
5185         }
5186         var d = ++key;
5187         for(var i = 0; i < len1; i++){
5188             c1[i]._qdiff = d;
5189         }
5190         var r = [];
5191         for(var i = 0, len = c2.length; i < len; i++){
5192             if(c2[i]._qdiff != d){
5193                 r[r.length] = c2[i];
5194             }
5195         }
5196         return r;
5197     }
5198
5199     function quickId(ns, mode, root, id){
5200         if(ns == root){
5201            var d = root.ownerDocument || root;
5202            return d.getElementById(id);
5203         }
5204         ns = getNodes(ns, mode, "*");
5205         return byId(ns, null, id);
5206     }
5207
5208     return {
5209         getStyle : function(el, name){
5210             return Roo.fly(el).getStyle(name);
5211         },
5212         /**
5213          * Compiles a selector/xpath query into a reusable function. The returned function
5214          * takes one parameter "root" (optional), which is the context node from where the query should start.
5215          * @param {String} selector The selector/xpath query
5216          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5217          * @return {Function}
5218          */
5219         compile : function(path, type){
5220             type = type || "select";
5221             
5222             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5223             var q = path, mode, lq;
5224             var tk = Roo.DomQuery.matchers;
5225             var tklen = tk.length;
5226             var mm;
5227
5228             // accept leading mode switch
5229             var lmode = q.match(modeRe);
5230             if(lmode && lmode[1]){
5231                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5232                 q = q.replace(lmode[1], "");
5233             }
5234             // strip leading slashes
5235             while(path.substr(0, 1)=="/"){
5236                 path = path.substr(1);
5237             }
5238
5239             while(q && lq != q){
5240                 lq = q;
5241                 var tm = q.match(tagTokenRe);
5242                 if(type == "select"){
5243                     if(tm){
5244                         if(tm[1] == "#"){
5245                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5246                         }else{
5247                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5248                         }
5249                         q = q.replace(tm[0], "");
5250                     }else if(q.substr(0, 1) != '@'){
5251                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5252                     }
5253                 }else{
5254                     if(tm){
5255                         if(tm[1] == "#"){
5256                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5257                         }else{
5258                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5259                         }
5260                         q = q.replace(tm[0], "");
5261                     }
5262                 }
5263                 while(!(mm = q.match(modeRe))){
5264                     var matched = false;
5265                     for(var j = 0; j < tklen; j++){
5266                         var t = tk[j];
5267                         var m = q.match(t.re);
5268                         if(m){
5269                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5270                                                     return m[i];
5271                                                 });
5272                             q = q.replace(m[0], "");
5273                             matched = true;
5274                             break;
5275                         }
5276                     }
5277                     // prevent infinite loop on bad selector
5278                     if(!matched){
5279                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5280                     }
5281                 }
5282                 if(mm[1]){
5283                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5284                     q = q.replace(mm[1], "");
5285                 }
5286             }
5287             fn[fn.length] = "return nodup(n);\n}";
5288             
5289              /** 
5290               * list of variables that need from compression as they are used by eval.
5291              *  eval:var:batch 
5292              *  eval:var:nodup
5293              *  eval:var:byTag
5294              *  eval:var:ById
5295              *  eval:var:getNodes
5296              *  eval:var:quickId
5297              *  eval:var:mode
5298              *  eval:var:root
5299              *  eval:var:n
5300              *  eval:var:byClassName
5301              *  eval:var:byPseudo
5302              *  eval:var:byAttribute
5303              *  eval:var:attrValue
5304              * 
5305              **/ 
5306             eval(fn.join(""));
5307             return f;
5308         },
5309
5310         /**
5311          * Selects a group of elements.
5312          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5313          * @param {Node} root (optional) The start of the query (defaults to document).
5314          * @return {Array}
5315          */
5316         select : function(path, root, type){
5317             if(!root || root == document){
5318                 root = document;
5319             }
5320             if(typeof root == "string"){
5321                 root = document.getElementById(root);
5322             }
5323             var paths = path.split(",");
5324             var results = [];
5325             for(var i = 0, len = paths.length; i < len; i++){
5326                 var p = paths[i].replace(trimRe, "");
5327                 if(!cache[p]){
5328                     cache[p] = Roo.DomQuery.compile(p);
5329                     if(!cache[p]){
5330                         throw p + " is not a valid selector";
5331                     }
5332                 }
5333                 var result = cache[p](root);
5334                 if(result && result != document){
5335                     results = results.concat(result);
5336                 }
5337             }
5338             if(paths.length > 1){
5339                 return nodup(results);
5340             }
5341             return results;
5342         },
5343
5344         /**
5345          * Selects a single element.
5346          * @param {String} selector The selector/xpath query
5347          * @param {Node} root (optional) The start of the query (defaults to document).
5348          * @return {Element}
5349          */
5350         selectNode : function(path, root){
5351             return Roo.DomQuery.select(path, root)[0];
5352         },
5353
5354         /**
5355          * Selects the value of a node, optionally replacing null with the defaultValue.
5356          * @param {String} selector The selector/xpath query
5357          * @param {Node} root (optional) The start of the query (defaults to document).
5358          * @param {String} defaultValue
5359          */
5360         selectValue : function(path, root, defaultValue){
5361             path = path.replace(trimRe, "");
5362             if(!valueCache[path]){
5363                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5364             }
5365             var n = valueCache[path](root);
5366             n = n[0] ? n[0] : n;
5367             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5368             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5369         },
5370
5371         /**
5372          * Selects the value of a node, parsing integers and floats.
5373          * @param {String} selector The selector/xpath query
5374          * @param {Node} root (optional) The start of the query (defaults to document).
5375          * @param {Number} defaultValue
5376          * @return {Number}
5377          */
5378         selectNumber : function(path, root, defaultValue){
5379             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5380             return parseFloat(v);
5381         },
5382
5383         /**
5384          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5385          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5386          * @param {String} selector The simple selector to test
5387          * @return {Boolean}
5388          */
5389         is : function(el, ss){
5390             if(typeof el == "string"){
5391                 el = document.getElementById(el);
5392             }
5393             var isArray = (el instanceof Array);
5394             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5395             return isArray ? (result.length == el.length) : (result.length > 0);
5396         },
5397
5398         /**
5399          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5400          * @param {Array} el An array of elements to filter
5401          * @param {String} selector The simple selector to test
5402          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5403          * the selector instead of the ones that match
5404          * @return {Array}
5405          */
5406         filter : function(els, ss, nonMatches){
5407             ss = ss.replace(trimRe, "");
5408             if(!simpleCache[ss]){
5409                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5410             }
5411             var result = simpleCache[ss](els);
5412             return nonMatches ? quickDiff(result, els) : result;
5413         },
5414
5415         /**
5416          * Collection of matching regular expressions and code snippets.
5417          */
5418         matchers : [{
5419                 re: /^\.([\w-]+)/,
5420                 select: 'n = byClassName(n, null, " {1} ");'
5421             }, {
5422                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5423                 select: 'n = byPseudo(n, "{1}", "{2}");'
5424             },{
5425                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5426                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5427             }, {
5428                 re: /^#([\w-]+)/,
5429                 select: 'n = byId(n, null, "{1}");'
5430             },{
5431                 re: /^@([\w-]+)/,
5432                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5433             }
5434         ],
5435
5436         /**
5437          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5438          * 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;.
5439          */
5440         operators : {
5441             "=" : function(a, v){
5442                 return a == v;
5443             },
5444             "!=" : function(a, v){
5445                 return a != v;
5446             },
5447             "^=" : function(a, v){
5448                 return a && a.substr(0, v.length) == v;
5449             },
5450             "$=" : function(a, v){
5451                 return a && a.substr(a.length-v.length) == v;
5452             },
5453             "*=" : function(a, v){
5454                 return a && a.indexOf(v) !== -1;
5455             },
5456             "%=" : function(a, v){
5457                 return (a % v) == 0;
5458             },
5459             "|=" : function(a, v){
5460                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5461             },
5462             "~=" : function(a, v){
5463                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5464             }
5465         },
5466
5467         /**
5468          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5469          * and the argument (if any) supplied in the selector.
5470          */
5471         pseudos : {
5472             "first-child" : function(c){
5473                 var r = [], ri = -1, n;
5474                 for(var i = 0, ci; ci = n = c[i]; i++){
5475                     while((n = n.previousSibling) && n.nodeType != 1);
5476                     if(!n){
5477                         r[++ri] = ci;
5478                     }
5479                 }
5480                 return r;
5481             },
5482
5483             "last-child" : function(c){
5484                 var r = [], ri = -1, n;
5485                 for(var i = 0, ci; ci = n = c[i]; i++){
5486                     while((n = n.nextSibling) && n.nodeType != 1);
5487                     if(!n){
5488                         r[++ri] = ci;
5489                     }
5490                 }
5491                 return r;
5492             },
5493
5494             "nth-child" : function(c, a) {
5495                 var r = [], ri = -1;
5496                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5497                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5498                 for(var i = 0, n; n = c[i]; i++){
5499                     var pn = n.parentNode;
5500                     if (batch != pn._batch) {
5501                         var j = 0;
5502                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5503                             if(cn.nodeType == 1){
5504                                cn.nodeIndex = ++j;
5505                             }
5506                         }
5507                         pn._batch = batch;
5508                     }
5509                     if (f == 1) {
5510                         if (l == 0 || n.nodeIndex == l){
5511                             r[++ri] = n;
5512                         }
5513                     } else if ((n.nodeIndex + l) % f == 0){
5514                         r[++ri] = n;
5515                     }
5516                 }
5517
5518                 return r;
5519             },
5520
5521             "only-child" : function(c){
5522                 var r = [], ri = -1;;
5523                 for(var i = 0, ci; ci = c[i]; i++){
5524                     if(!prev(ci) && !next(ci)){
5525                         r[++ri] = ci;
5526                     }
5527                 }
5528                 return r;
5529             },
5530
5531             "empty" : function(c){
5532                 var r = [], ri = -1;
5533                 for(var i = 0, ci; ci = c[i]; i++){
5534                     var cns = ci.childNodes, j = 0, cn, empty = true;
5535                     while(cn = cns[j]){
5536                         ++j;
5537                         if(cn.nodeType == 1 || cn.nodeType == 3){
5538                             empty = false;
5539                             break;
5540                         }
5541                     }
5542                     if(empty){
5543                         r[++ri] = ci;
5544                     }
5545                 }
5546                 return r;
5547             },
5548
5549             "contains" : function(c, v){
5550                 var r = [], ri = -1;
5551                 for(var i = 0, ci; ci = c[i]; i++){
5552                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5553                         r[++ri] = ci;
5554                     }
5555                 }
5556                 return r;
5557             },
5558
5559             "nodeValue" : function(c, v){
5560                 var r = [], ri = -1;
5561                 for(var i = 0, ci; ci = c[i]; i++){
5562                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5563                         r[++ri] = ci;
5564                     }
5565                 }
5566                 return r;
5567             },
5568
5569             "checked" : function(c){
5570                 var r = [], ri = -1;
5571                 for(var i = 0, ci; ci = c[i]; i++){
5572                     if(ci.checked == true){
5573                         r[++ri] = ci;
5574                     }
5575                 }
5576                 return r;
5577             },
5578
5579             "not" : function(c, ss){
5580                 return Roo.DomQuery.filter(c, ss, true);
5581             },
5582
5583             "odd" : function(c){
5584                 return this["nth-child"](c, "odd");
5585             },
5586
5587             "even" : function(c){
5588                 return this["nth-child"](c, "even");
5589             },
5590
5591             "nth" : function(c, a){
5592                 return c[a-1] || [];
5593             },
5594
5595             "first" : function(c){
5596                 return c[0] || [];
5597             },
5598
5599             "last" : function(c){
5600                 return c[c.length-1] || [];
5601             },
5602
5603             "has" : function(c, ss){
5604                 var s = Roo.DomQuery.select;
5605                 var r = [], ri = -1;
5606                 for(var i = 0, ci; ci = c[i]; i++){
5607                     if(s(ss, ci).length > 0){
5608                         r[++ri] = ci;
5609                     }
5610                 }
5611                 return r;
5612             },
5613
5614             "next" : function(c, ss){
5615                 var is = Roo.DomQuery.is;
5616                 var r = [], ri = -1;
5617                 for(var i = 0, ci; ci = c[i]; i++){
5618                     var n = next(ci);
5619                     if(n && is(n, ss)){
5620                         r[++ri] = ci;
5621                     }
5622                 }
5623                 return r;
5624             },
5625
5626             "prev" : function(c, ss){
5627                 var is = Roo.DomQuery.is;
5628                 var r = [], ri = -1;
5629                 for(var i = 0, ci; ci = c[i]; i++){
5630                     var n = prev(ci);
5631                     if(n && is(n, ss)){
5632                         r[++ri] = ci;
5633                     }
5634                 }
5635                 return r;
5636             }
5637         }
5638     };
5639 }();
5640
5641 /**
5642  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5643  * @param {String} path The selector/xpath query
5644  * @param {Node} root (optional) The start of the query (defaults to document).
5645  * @return {Array}
5646  * @member Roo
5647  * @method query
5648  */
5649 Roo.query = Roo.DomQuery.select;
5650 /*
5651  * Based on:
5652  * Ext JS Library 1.1.1
5653  * Copyright(c) 2006-2007, Ext JS, LLC.
5654  *
5655  * Originally Released Under LGPL - original licence link has changed is not relivant.
5656  *
5657  * Fork - LGPL
5658  * <script type="text/javascript">
5659  */
5660
5661 /**
5662  * @class Roo.util.Observable
5663  * Base class that provides a common interface for publishing events. Subclasses are expected to
5664  * to have a property "events" with all the events defined.<br>
5665  * For example:
5666  * <pre><code>
5667  Employee = function(name){
5668     this.name = name;
5669     this.addEvents({
5670         "fired" : true,
5671         "quit" : true
5672     });
5673  }
5674  Roo.extend(Employee, Roo.util.Observable);
5675 </code></pre>
5676  * @param {Object} config properties to use (incuding events / listeners)
5677  */
5678
5679 Roo.util.Observable = function(cfg){
5680     
5681     cfg = cfg|| {};
5682     this.addEvents(cfg.events || {});
5683     if (cfg.events) {
5684         delete cfg.events; // make sure
5685     }
5686      
5687     Roo.apply(this, cfg);
5688     
5689     if(this.listeners){
5690         this.on(this.listeners);
5691         delete this.listeners;
5692     }
5693 };
5694 Roo.util.Observable.prototype = {
5695     /** 
5696  * @cfg {Object} listeners  list of events and functions to call for this object, 
5697  * For example :
5698  * <pre><code>
5699     listeners :  { 
5700        'click' : function(e) {
5701            ..... 
5702         } ,
5703         .... 
5704     } 
5705   </code></pre>
5706  */
5707     
5708     
5709     /**
5710      * Fires the specified event with the passed parameters (minus the event name).
5711      * @param {String} eventName
5712      * @param {Object...} args Variable number of parameters are passed to handlers
5713      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5714      */
5715     fireEvent : function(){
5716         var ce = this.events[arguments[0].toLowerCase()];
5717         if(typeof ce == "object"){
5718             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5719         }else{
5720             return true;
5721         }
5722     },
5723
5724     // private
5725     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5726
5727     /**
5728      * Appends an event handler to this component
5729      * @param {String}   eventName The type of event to listen for
5730      * @param {Function} handler The method the event invokes
5731      * @param {Object}   scope (optional) The scope in which to execute the handler
5732      * function. The handler function's "this" context.
5733      * @param {Object}   options (optional) An object containing handler configuration
5734      * properties. This may contain any of the following properties:<ul>
5735      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5736      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5737      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5738      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5739      * by the specified number of milliseconds. If the event fires again within that time, the original
5740      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5741      * </ul><br>
5742      * <p>
5743      * <b>Combining Options</b><br>
5744      * Using the options argument, it is possible to combine different types of listeners:<br>
5745      * <br>
5746      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5747                 <pre><code>
5748                 el.on('click', this.onClick, this, {
5749                         single: true,
5750                 delay: 100,
5751                 forumId: 4
5752                 });
5753                 </code></pre>
5754      * <p>
5755      * <b>Attaching multiple handlers in 1 call</b><br>
5756      * The method also allows for a single argument to be passed which is a config object containing properties
5757      * which specify multiple handlers.
5758      * <pre><code>
5759                 el.on({
5760                         'click': {
5761                         fn: this.onClick,
5762                         scope: this,
5763                         delay: 100
5764                 }, 
5765                 'mouseover': {
5766                         fn: this.onMouseOver,
5767                         scope: this
5768                 },
5769                 'mouseout': {
5770                         fn: this.onMouseOut,
5771                         scope: this
5772                 }
5773                 });
5774                 </code></pre>
5775      * <p>
5776      * Or a shorthand syntax which passes the same scope object to all handlers:
5777         <pre><code>
5778                 el.on({
5779                         'click': this.onClick,
5780                 'mouseover': this.onMouseOver,
5781                 'mouseout': this.onMouseOut,
5782                 scope: this
5783                 });
5784                 </code></pre>
5785      */
5786     addListener : function(eventName, fn, scope, o){
5787         if(typeof eventName == "object"){
5788             o = eventName;
5789             for(var e in o){
5790                 if(this.filterOptRe.test(e)){
5791                     continue;
5792                 }
5793                 if(typeof o[e] == "function"){
5794                     // shared options
5795                     this.addListener(e, o[e], o.scope,  o);
5796                 }else{
5797                     // individual options
5798                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5799                 }
5800             }
5801             return;
5802         }
5803         o = (!o || typeof o == "boolean") ? {} : o;
5804         eventName = eventName.toLowerCase();
5805         var ce = this.events[eventName] || true;
5806         if(typeof ce == "boolean"){
5807             ce = new Roo.util.Event(this, eventName);
5808             this.events[eventName] = ce;
5809         }
5810         ce.addListener(fn, scope, o);
5811     },
5812
5813     /**
5814      * Removes a listener
5815      * @param {String}   eventName     The type of event to listen for
5816      * @param {Function} handler        The handler to remove
5817      * @param {Object}   scope  (optional) The scope (this object) for the handler
5818      */
5819     removeListener : function(eventName, fn, scope){
5820         var ce = this.events[eventName.toLowerCase()];
5821         if(typeof ce == "object"){
5822             ce.removeListener(fn, scope);
5823         }
5824     },
5825
5826     /**
5827      * Removes all listeners for this object
5828      */
5829     purgeListeners : function(){
5830         for(var evt in this.events){
5831             if(typeof this.events[evt] == "object"){
5832                  this.events[evt].clearListeners();
5833             }
5834         }
5835     },
5836
5837     relayEvents : function(o, events){
5838         var createHandler = function(ename){
5839             return function(){
5840                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5841             };
5842         };
5843         for(var i = 0, len = events.length; i < len; i++){
5844             var ename = events[i];
5845             if(!this.events[ename]){ this.events[ename] = true; };
5846             o.on(ename, createHandler(ename), this);
5847         }
5848     },
5849
5850     /**
5851      * Used to define events on this Observable
5852      * @param {Object} object The object with the events defined
5853      */
5854     addEvents : function(o){
5855         if(!this.events){
5856             this.events = {};
5857         }
5858         Roo.applyIf(this.events, o);
5859     },
5860
5861     /**
5862      * Checks to see if this object has any listeners for a specified event
5863      * @param {String} eventName The name of the event to check for
5864      * @return {Boolean} True if the event is being listened for, else false
5865      */
5866     hasListener : function(eventName){
5867         var e = this.events[eventName];
5868         return typeof e == "object" && e.listeners.length > 0;
5869     }
5870 };
5871 /**
5872  * Appends an event handler to this element (shorthand for addListener)
5873  * @param {String}   eventName     The type of event to listen for
5874  * @param {Function} handler        The method the event invokes
5875  * @param {Object}   scope (optional) The scope in which to execute the handler
5876  * function. The handler function's "this" context.
5877  * @param {Object}   options  (optional)
5878  * @method
5879  */
5880 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5881 /**
5882  * Removes a listener (shorthand for removeListener)
5883  * @param {String}   eventName     The type of event to listen for
5884  * @param {Function} handler        The handler to remove
5885  * @param {Object}   scope  (optional) The scope (this object) for the handler
5886  * @method
5887  */
5888 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5889
5890 /**
5891  * Starts capture on the specified Observable. All events will be passed
5892  * to the supplied function with the event name + standard signature of the event
5893  * <b>before</b> the event is fired. If the supplied function returns false,
5894  * the event will not fire.
5895  * @param {Observable} o The Observable to capture
5896  * @param {Function} fn The function to call
5897  * @param {Object} scope (optional) The scope (this object) for the fn
5898  * @static
5899  */
5900 Roo.util.Observable.capture = function(o, fn, scope){
5901     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5902 };
5903
5904 /**
5905  * Removes <b>all</b> added captures from the Observable.
5906  * @param {Observable} o The Observable to release
5907  * @static
5908  */
5909 Roo.util.Observable.releaseCapture = function(o){
5910     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5911 };
5912
5913 (function(){
5914
5915     var createBuffered = function(h, o, scope){
5916         var task = new Roo.util.DelayedTask();
5917         return function(){
5918             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5919         };
5920     };
5921
5922     var createSingle = function(h, e, fn, scope){
5923         return function(){
5924             e.removeListener(fn, scope);
5925             return h.apply(scope, arguments);
5926         };
5927     };
5928
5929     var createDelayed = function(h, o, scope){
5930         return function(){
5931             var args = Array.prototype.slice.call(arguments, 0);
5932             setTimeout(function(){
5933                 h.apply(scope, args);
5934             }, o.delay || 10);
5935         };
5936     };
5937
5938     Roo.util.Event = function(obj, name){
5939         this.name = name;
5940         this.obj = obj;
5941         this.listeners = [];
5942     };
5943
5944     Roo.util.Event.prototype = {
5945         addListener : function(fn, scope, options){
5946             var o = options || {};
5947             scope = scope || this.obj;
5948             if(!this.isListening(fn, scope)){
5949                 var l = {fn: fn, scope: scope, options: o};
5950                 var h = fn;
5951                 if(o.delay){
5952                     h = createDelayed(h, o, scope);
5953                 }
5954                 if(o.single){
5955                     h = createSingle(h, this, fn, scope);
5956                 }
5957                 if(o.buffer){
5958                     h = createBuffered(h, o, scope);
5959                 }
5960                 l.fireFn = h;
5961                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5962                     this.listeners.push(l);
5963                 }else{
5964                     this.listeners = this.listeners.slice(0);
5965                     this.listeners.push(l);
5966                 }
5967             }
5968         },
5969
5970         findListener : function(fn, scope){
5971             scope = scope || this.obj;
5972             var ls = this.listeners;
5973             for(var i = 0, len = ls.length; i < len; i++){
5974                 var l = ls[i];
5975                 if(l.fn == fn && l.scope == scope){
5976                     return i;
5977                 }
5978             }
5979             return -1;
5980         },
5981
5982         isListening : function(fn, scope){
5983             return this.findListener(fn, scope) != -1;
5984         },
5985
5986         removeListener : function(fn, scope){
5987             var index;
5988             if((index = this.findListener(fn, scope)) != -1){
5989                 if(!this.firing){
5990                     this.listeners.splice(index, 1);
5991                 }else{
5992                     this.listeners = this.listeners.slice(0);
5993                     this.listeners.splice(index, 1);
5994                 }
5995                 return true;
5996             }
5997             return false;
5998         },
5999
6000         clearListeners : function(){
6001             this.listeners = [];
6002         },
6003
6004         fire : function(){
6005             var ls = this.listeners, scope, len = ls.length;
6006             if(len > 0){
6007                 this.firing = true;
6008                 var args = Array.prototype.slice.call(arguments, 0);
6009                 for(var i = 0; i < len; i++){
6010                     var l = ls[i];
6011                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6012                         this.firing = false;
6013                         return false;
6014                     }
6015                 }
6016                 this.firing = false;
6017             }
6018             return true;
6019         }
6020     };
6021 })();/*
6022  * Based on:
6023  * Ext JS Library 1.1.1
6024  * Copyright(c) 2006-2007, Ext JS, LLC.
6025  *
6026  * Originally Released Under LGPL - original licence link has changed is not relivant.
6027  *
6028  * Fork - LGPL
6029  * <script type="text/javascript">
6030  */
6031
6032 /**
6033  * @class Roo.EventManager
6034  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6035  * several useful events directly.
6036  * See {@link Roo.EventObject} for more details on normalized event objects.
6037  * @singleton
6038  */
6039 Roo.EventManager = function(){
6040     var docReadyEvent, docReadyProcId, docReadyState = false;
6041     var resizeEvent, resizeTask, textEvent, textSize;
6042     var E = Roo.lib.Event;
6043     var D = Roo.lib.Dom;
6044
6045
6046     var fireDocReady = function(){
6047         if(!docReadyState){
6048             docReadyState = true;
6049             Roo.isReady = true;
6050             if(docReadyProcId){
6051                 clearInterval(docReadyProcId);
6052             }
6053             if(Roo.isGecko || Roo.isOpera) {
6054                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6055             }
6056             if(Roo.isIE){
6057                 var defer = document.getElementById("ie-deferred-loader");
6058                 if(defer){
6059                     defer.onreadystatechange = null;
6060                     defer.parentNode.removeChild(defer);
6061                 }
6062             }
6063             if(docReadyEvent){
6064                 docReadyEvent.fire();
6065                 docReadyEvent.clearListeners();
6066             }
6067         }
6068     };
6069     
6070     var initDocReady = function(){
6071         docReadyEvent = new Roo.util.Event();
6072         if(Roo.isGecko || Roo.isOpera) {
6073             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6074         }else if(Roo.isIE){
6075             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6076             var defer = document.getElementById("ie-deferred-loader");
6077             defer.onreadystatechange = function(){
6078                 if(this.readyState == "complete"){
6079                     fireDocReady();
6080                 }
6081             };
6082         }else if(Roo.isSafari){ 
6083             docReadyProcId = setInterval(function(){
6084                 var rs = document.readyState;
6085                 if(rs == "complete") {
6086                     fireDocReady();     
6087                  }
6088             }, 10);
6089         }
6090         // no matter what, make sure it fires on load
6091         E.on(window, "load", fireDocReady);
6092     };
6093
6094     var createBuffered = function(h, o){
6095         var task = new Roo.util.DelayedTask(h);
6096         return function(e){
6097             // create new event object impl so new events don't wipe out properties
6098             e = new Roo.EventObjectImpl(e);
6099             task.delay(o.buffer, h, null, [e]);
6100         };
6101     };
6102
6103     var createSingle = function(h, el, ename, fn){
6104         return function(e){
6105             Roo.EventManager.removeListener(el, ename, fn);
6106             h(e);
6107         };
6108     };
6109
6110     var createDelayed = function(h, o){
6111         return function(e){
6112             // create new event object impl so new events don't wipe out properties
6113             e = new Roo.EventObjectImpl(e);
6114             setTimeout(function(){
6115                 h(e);
6116             }, o.delay || 10);
6117         };
6118     };
6119
6120     var listen = function(element, ename, opt, fn, scope){
6121         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6122         fn = fn || o.fn; scope = scope || o.scope;
6123         var el = Roo.getDom(element);
6124         if(!el){
6125             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6126         }
6127         var h = function(e){
6128             e = Roo.EventObject.setEvent(e);
6129             var t;
6130             if(o.delegate){
6131                 t = e.getTarget(o.delegate, el);
6132                 if(!t){
6133                     return;
6134                 }
6135             }else{
6136                 t = e.target;
6137             }
6138             if(o.stopEvent === true){
6139                 e.stopEvent();
6140             }
6141             if(o.preventDefault === true){
6142                e.preventDefault();
6143             }
6144             if(o.stopPropagation === true){
6145                 e.stopPropagation();
6146             }
6147
6148             if(o.normalized === false){
6149                 e = e.browserEvent;
6150             }
6151
6152             fn.call(scope || el, e, t, o);
6153         };
6154         if(o.delay){
6155             h = createDelayed(h, o);
6156         }
6157         if(o.single){
6158             h = createSingle(h, el, ename, fn);
6159         }
6160         if(o.buffer){
6161             h = createBuffered(h, o);
6162         }
6163         fn._handlers = fn._handlers || [];
6164         fn._handlers.push([Roo.id(el), ename, h]);
6165
6166         E.on(el, ename, h);
6167         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6168             el.addEventListener("DOMMouseScroll", h, false);
6169             E.on(window, 'unload', function(){
6170                 el.removeEventListener("DOMMouseScroll", h, false);
6171             });
6172         }
6173         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6174             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6175         }
6176         return h;
6177     };
6178
6179     var stopListening = function(el, ename, fn){
6180         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6181         if(hds){
6182             for(var i = 0, len = hds.length; i < len; i++){
6183                 var h = hds[i];
6184                 if(h[0] == id && h[1] == ename){
6185                     hd = h[2];
6186                     hds.splice(i, 1);
6187                     break;
6188                 }
6189             }
6190         }
6191         E.un(el, ename, hd);
6192         el = Roo.getDom(el);
6193         if(ename == "mousewheel" && el.addEventListener){
6194             el.removeEventListener("DOMMouseScroll", hd, false);
6195         }
6196         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6197             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6198         }
6199     };
6200
6201     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6202     
6203     var pub = {
6204         
6205         
6206         /** 
6207          * Fix for doc tools
6208          * @scope Roo.EventManager
6209          */
6210         
6211         
6212         /** 
6213          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6214          * object with a Roo.EventObject
6215          * @param {Function} fn        The method the event invokes
6216          * @param {Object}   scope    An object that becomes the scope of the handler
6217          * @param {boolean}  override If true, the obj passed in becomes
6218          *                             the execution scope of the listener
6219          * @return {Function} The wrapped function
6220          * @deprecated
6221          */
6222         wrap : function(fn, scope, override){
6223             return function(e){
6224                 Roo.EventObject.setEvent(e);
6225                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6226             };
6227         },
6228         
6229         /**
6230      * Appends an event handler to an element (shorthand for addListener)
6231      * @param {String/HTMLElement}   element        The html element or id to assign the
6232      * @param {String}   eventName The type of event to listen for
6233      * @param {Function} handler The method the event invokes
6234      * @param {Object}   scope (optional) The scope in which to execute the handler
6235      * function. The handler function's "this" context.
6236      * @param {Object}   options (optional) An object containing handler configuration
6237      * properties. This may contain any of the following properties:<ul>
6238      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6239      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6240      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6241      * <li>preventDefault {Boolean} True to prevent the default action</li>
6242      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6243      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6244      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6245      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6246      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6247      * by the specified number of milliseconds. If the event fires again within that time, the original
6248      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6249      * </ul><br>
6250      * <p>
6251      * <b>Combining Options</b><br>
6252      * Using the options argument, it is possible to combine different types of listeners:<br>
6253      * <br>
6254      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6255      * Code:<pre><code>
6256 el.on('click', this.onClick, this, {
6257     single: true,
6258     delay: 100,
6259     stopEvent : true,
6260     forumId: 4
6261 });</code></pre>
6262      * <p>
6263      * <b>Attaching multiple handlers in 1 call</b><br>
6264       * The method also allows for a single argument to be passed which is a config object containing properties
6265      * which specify multiple handlers.
6266      * <p>
6267      * Code:<pre><code>
6268 el.on({
6269     'click' : {
6270         fn: this.onClick
6271         scope: this,
6272         delay: 100
6273     },
6274     'mouseover' : {
6275         fn: this.onMouseOver
6276         scope: this
6277     },
6278     'mouseout' : {
6279         fn: this.onMouseOut
6280         scope: this
6281     }
6282 });</code></pre>
6283      * <p>
6284      * Or a shorthand syntax:<br>
6285      * Code:<pre><code>
6286 el.on({
6287     'click' : this.onClick,
6288     'mouseover' : this.onMouseOver,
6289     'mouseout' : this.onMouseOut
6290     scope: this
6291 });</code></pre>
6292      */
6293         addListener : function(element, eventName, fn, scope, options){
6294             if(typeof eventName == "object"){
6295                 var o = eventName;
6296                 for(var e in o){
6297                     if(propRe.test(e)){
6298                         continue;
6299                     }
6300                     if(typeof o[e] == "function"){
6301                         // shared options
6302                         listen(element, e, o, o[e], o.scope);
6303                     }else{
6304                         // individual options
6305                         listen(element, e, o[e]);
6306                     }
6307                 }
6308                 return;
6309             }
6310             return listen(element, eventName, options, fn, scope);
6311         },
6312         
6313         /**
6314          * Removes an event handler
6315          *
6316          * @param {String/HTMLElement}   element        The id or html element to remove the 
6317          *                             event from
6318          * @param {String}   eventName     The type of event
6319          * @param {Function} fn
6320          * @return {Boolean} True if a listener was actually removed
6321          */
6322         removeListener : function(element, eventName, fn){
6323             return stopListening(element, eventName, fn);
6324         },
6325         
6326         /**
6327          * Fires when the document is ready (before onload and before images are loaded). Can be 
6328          * accessed shorthanded Roo.onReady().
6329          * @param {Function} fn        The method the event invokes
6330          * @param {Object}   scope    An  object that becomes the scope of the handler
6331          * @param {boolean}  options
6332          */
6333         onDocumentReady : function(fn, scope, options){
6334             if(docReadyState){ // if it already fired
6335                 docReadyEvent.addListener(fn, scope, options);
6336                 docReadyEvent.fire();
6337                 docReadyEvent.clearListeners();
6338                 return;
6339             }
6340             if(!docReadyEvent){
6341                 initDocReady();
6342             }
6343             docReadyEvent.addListener(fn, scope, options);
6344         },
6345         
6346         /**
6347          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6348          * @param {Function} fn        The method the event invokes
6349          * @param {Object}   scope    An object that becomes the scope of the handler
6350          * @param {boolean}  options
6351          */
6352         onWindowResize : function(fn, scope, options){
6353             if(!resizeEvent){
6354                 resizeEvent = new Roo.util.Event();
6355                 resizeTask = new Roo.util.DelayedTask(function(){
6356                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6357                 });
6358                 E.on(window, "resize", function(){
6359                     if(Roo.isIE){
6360                         resizeTask.delay(50);
6361                     }else{
6362                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6363                     }
6364                 });
6365             }
6366             resizeEvent.addListener(fn, scope, options);
6367         },
6368
6369         /**
6370          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6371          * @param {Function} fn        The method the event invokes
6372          * @param {Object}   scope    An object that becomes the scope of the handler
6373          * @param {boolean}  options
6374          */
6375         onTextResize : function(fn, scope, options){
6376             if(!textEvent){
6377                 textEvent = new Roo.util.Event();
6378                 var textEl = new Roo.Element(document.createElement('div'));
6379                 textEl.dom.className = 'x-text-resize';
6380                 textEl.dom.innerHTML = 'X';
6381                 textEl.appendTo(document.body);
6382                 textSize = textEl.dom.offsetHeight;
6383                 setInterval(function(){
6384                     if(textEl.dom.offsetHeight != textSize){
6385                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6386                     }
6387                 }, this.textResizeInterval);
6388             }
6389             textEvent.addListener(fn, scope, options);
6390         },
6391
6392         /**
6393          * Removes the passed window resize listener.
6394          * @param {Function} fn        The method the event invokes
6395          * @param {Object}   scope    The scope of handler
6396          */
6397         removeResizeListener : function(fn, scope){
6398             if(resizeEvent){
6399                 resizeEvent.removeListener(fn, scope);
6400             }
6401         },
6402
6403         // private
6404         fireResize : function(){
6405             if(resizeEvent){
6406                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6407             }   
6408         },
6409         /**
6410          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6411          */
6412         ieDeferSrc : false,
6413         /**
6414          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6415          */
6416         textResizeInterval : 50
6417     };
6418     
6419     /**
6420      * Fix for doc tools
6421      * @scopeAlias pub=Roo.EventManager
6422      */
6423     
6424      /**
6425      * Appends an event handler to an element (shorthand for addListener)
6426      * @param {String/HTMLElement}   element        The html element or id to assign the
6427      * @param {String}   eventName The type of event to listen for
6428      * @param {Function} handler The method the event invokes
6429      * @param {Object}   scope (optional) The scope in which to execute the handler
6430      * function. The handler function's "this" context.
6431      * @param {Object}   options (optional) An object containing handler configuration
6432      * properties. This may contain any of the following properties:<ul>
6433      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6434      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6435      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6436      * <li>preventDefault {Boolean} True to prevent the default action</li>
6437      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6438      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6439      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6440      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6441      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6442      * by the specified number of milliseconds. If the event fires again within that time, the original
6443      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6444      * </ul><br>
6445      * <p>
6446      * <b>Combining Options</b><br>
6447      * Using the options argument, it is possible to combine different types of listeners:<br>
6448      * <br>
6449      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6450      * Code:<pre><code>
6451 el.on('click', this.onClick, this, {
6452     single: true,
6453     delay: 100,
6454     stopEvent : true,
6455     forumId: 4
6456 });</code></pre>
6457      * <p>
6458      * <b>Attaching multiple handlers in 1 call</b><br>
6459       * The method also allows for a single argument to be passed which is a config object containing properties
6460      * which specify multiple handlers.
6461      * <p>
6462      * Code:<pre><code>
6463 el.on({
6464     'click' : {
6465         fn: this.onClick
6466         scope: this,
6467         delay: 100
6468     },
6469     'mouseover' : {
6470         fn: this.onMouseOver
6471         scope: this
6472     },
6473     'mouseout' : {
6474         fn: this.onMouseOut
6475         scope: this
6476     }
6477 });</code></pre>
6478      * <p>
6479      * Or a shorthand syntax:<br>
6480      * Code:<pre><code>
6481 el.on({
6482     'click' : this.onClick,
6483     'mouseover' : this.onMouseOver,
6484     'mouseout' : this.onMouseOut
6485     scope: this
6486 });</code></pre>
6487      */
6488     pub.on = pub.addListener;
6489     pub.un = pub.removeListener;
6490
6491     pub.stoppedMouseDownEvent = new Roo.util.Event();
6492     return pub;
6493 }();
6494 /**
6495   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6496   * @param {Function} fn        The method the event invokes
6497   * @param {Object}   scope    An  object that becomes the scope of the handler
6498   * @param {boolean}  override If true, the obj passed in becomes
6499   *                             the execution scope of the listener
6500   * @member Roo
6501   * @method onReady
6502  */
6503 Roo.onReady = Roo.EventManager.onDocumentReady;
6504
6505 Roo.onReady(function(){
6506     var bd = Roo.get(document.body);
6507     if(!bd){ return; }
6508
6509     var cls = [
6510             Roo.isIE ? "roo-ie"
6511             : Roo.isGecko ? "roo-gecko"
6512             : Roo.isOpera ? "roo-opera"
6513             : Roo.isSafari ? "roo-safari" : ""];
6514
6515     if(Roo.isMac){
6516         cls.push("roo-mac");
6517     }
6518     if(Roo.isLinux){
6519         cls.push("roo-linux");
6520     }
6521     if(Roo.isBorderBox){
6522         cls.push('roo-border-box');
6523     }
6524     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6525         var p = bd.dom.parentNode;
6526         if(p){
6527             p.className += ' roo-strict';
6528         }
6529     }
6530     bd.addClass(cls.join(' '));
6531 });
6532
6533 /**
6534  * @class Roo.EventObject
6535  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6536  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6537  * Example:
6538  * <pre><code>
6539  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6540     e.preventDefault();
6541     var target = e.getTarget();
6542     ...
6543  }
6544  var myDiv = Roo.get("myDiv");
6545  myDiv.on("click", handleClick);
6546  //or
6547  Roo.EventManager.on("myDiv", 'click', handleClick);
6548  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6549  </code></pre>
6550  * @singleton
6551  */
6552 Roo.EventObject = function(){
6553     
6554     var E = Roo.lib.Event;
6555     
6556     // safari keypress events for special keys return bad keycodes
6557     var safariKeys = {
6558         63234 : 37, // left
6559         63235 : 39, // right
6560         63232 : 38, // up
6561         63233 : 40, // down
6562         63276 : 33, // page up
6563         63277 : 34, // page down
6564         63272 : 46, // delete
6565         63273 : 36, // home
6566         63275 : 35  // end
6567     };
6568
6569     // normalize button clicks
6570     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6571                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6572
6573     Roo.EventObjectImpl = function(e){
6574         if(e){
6575             this.setEvent(e.browserEvent || e);
6576         }
6577     };
6578     Roo.EventObjectImpl.prototype = {
6579         /**
6580          * Used to fix doc tools.
6581          * @scope Roo.EventObject.prototype
6582          */
6583             
6584
6585         
6586         
6587         /** The normal browser event */
6588         browserEvent : null,
6589         /** The button pressed in a mouse event */
6590         button : -1,
6591         /** True if the shift key was down during the event */
6592         shiftKey : false,
6593         /** True if the control key was down during the event */
6594         ctrlKey : false,
6595         /** True if the alt key was down during the event */
6596         altKey : false,
6597
6598         /** Key constant 
6599         * @type Number */
6600         BACKSPACE : 8,
6601         /** Key constant 
6602         * @type Number */
6603         TAB : 9,
6604         /** Key constant 
6605         * @type Number */
6606         RETURN : 13,
6607         /** Key constant 
6608         * @type Number */
6609         ENTER : 13,
6610         /** Key constant 
6611         * @type Number */
6612         SHIFT : 16,
6613         /** Key constant 
6614         * @type Number */
6615         CONTROL : 17,
6616         /** Key constant 
6617         * @type Number */
6618         ESC : 27,
6619         /** Key constant 
6620         * @type Number */
6621         SPACE : 32,
6622         /** Key constant 
6623         * @type Number */
6624         PAGEUP : 33,
6625         /** Key constant 
6626         * @type Number */
6627         PAGEDOWN : 34,
6628         /** Key constant 
6629         * @type Number */
6630         END : 35,
6631         /** Key constant 
6632         * @type Number */
6633         HOME : 36,
6634         /** Key constant 
6635         * @type Number */
6636         LEFT : 37,
6637         /** Key constant 
6638         * @type Number */
6639         UP : 38,
6640         /** Key constant 
6641         * @type Number */
6642         RIGHT : 39,
6643         /** Key constant 
6644         * @type Number */
6645         DOWN : 40,
6646         /** Key constant 
6647         * @type Number */
6648         DELETE : 46,
6649         /** Key constant 
6650         * @type Number */
6651         F5 : 116,
6652
6653            /** @private */
6654         setEvent : function(e){
6655             if(e == this || (e && e.browserEvent)){ // already wrapped
6656                 return e;
6657             }
6658             this.browserEvent = e;
6659             if(e){
6660                 // normalize buttons
6661                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6662                 if(e.type == 'click' && this.button == -1){
6663                     this.button = 0;
6664                 }
6665                 this.type = e.type;
6666                 this.shiftKey = e.shiftKey;
6667                 // mac metaKey behaves like ctrlKey
6668                 this.ctrlKey = e.ctrlKey || e.metaKey;
6669                 this.altKey = e.altKey;
6670                 // in getKey these will be normalized for the mac
6671                 this.keyCode = e.keyCode;
6672                 // keyup warnings on firefox.
6673                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6674                 // cache the target for the delayed and or buffered events
6675                 this.target = E.getTarget(e);
6676                 // same for XY
6677                 this.xy = E.getXY(e);
6678             }else{
6679                 this.button = -1;
6680                 this.shiftKey = false;
6681                 this.ctrlKey = false;
6682                 this.altKey = false;
6683                 this.keyCode = 0;
6684                 this.charCode =0;
6685                 this.target = null;
6686                 this.xy = [0, 0];
6687             }
6688             return this;
6689         },
6690
6691         /**
6692          * Stop the event (preventDefault and stopPropagation)
6693          */
6694         stopEvent : function(){
6695             if(this.browserEvent){
6696                 if(this.browserEvent.type == 'mousedown'){
6697                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6698                 }
6699                 E.stopEvent(this.browserEvent);
6700             }
6701         },
6702
6703         /**
6704          * Prevents the browsers default handling of the event.
6705          */
6706         preventDefault : function(){
6707             if(this.browserEvent){
6708                 E.preventDefault(this.browserEvent);
6709             }
6710         },
6711
6712         /** @private */
6713         isNavKeyPress : function(){
6714             var k = this.keyCode;
6715             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6716             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6717         },
6718
6719         isSpecialKey : function(){
6720             var k = this.keyCode;
6721             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6722             (k == 16) || (k == 17) ||
6723             (k >= 18 && k <= 20) ||
6724             (k >= 33 && k <= 35) ||
6725             (k >= 36 && k <= 39) ||
6726             (k >= 44 && k <= 45);
6727         },
6728         /**
6729          * Cancels bubbling of the event.
6730          */
6731         stopPropagation : function(){
6732             if(this.browserEvent){
6733                 if(this.type == 'mousedown'){
6734                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6735                 }
6736                 E.stopPropagation(this.browserEvent);
6737             }
6738         },
6739
6740         /**
6741          * Gets the key code for the event.
6742          * @return {Number}
6743          */
6744         getCharCode : function(){
6745             return this.charCode || this.keyCode;
6746         },
6747
6748         /**
6749          * Returns a normalized keyCode for the event.
6750          * @return {Number} The key code
6751          */
6752         getKey : function(){
6753             var k = this.keyCode || this.charCode;
6754             return Roo.isSafari ? (safariKeys[k] || k) : k;
6755         },
6756
6757         /**
6758          * Gets the x coordinate of the event.
6759          * @return {Number}
6760          */
6761         getPageX : function(){
6762             return this.xy[0];
6763         },
6764
6765         /**
6766          * Gets the y coordinate of the event.
6767          * @return {Number}
6768          */
6769         getPageY : function(){
6770             return this.xy[1];
6771         },
6772
6773         /**
6774          * Gets the time of the event.
6775          * @return {Number}
6776          */
6777         getTime : function(){
6778             if(this.browserEvent){
6779                 return E.getTime(this.browserEvent);
6780             }
6781             return null;
6782         },
6783
6784         /**
6785          * Gets the page coordinates of the event.
6786          * @return {Array} The xy values like [x, y]
6787          */
6788         getXY : function(){
6789             return this.xy;
6790         },
6791
6792         /**
6793          * Gets the target for the event.
6794          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6795          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6796                 search as a number or element (defaults to 10 || document.body)
6797          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6798          * @return {HTMLelement}
6799          */
6800         getTarget : function(selector, maxDepth, returnEl){
6801             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6802         },
6803         /**
6804          * Gets the related target.
6805          * @return {HTMLElement}
6806          */
6807         getRelatedTarget : function(){
6808             if(this.browserEvent){
6809                 return E.getRelatedTarget(this.browserEvent);
6810             }
6811             return null;
6812         },
6813
6814         /**
6815          * Normalizes mouse wheel delta across browsers
6816          * @return {Number} The delta
6817          */
6818         getWheelDelta : function(){
6819             var e = this.browserEvent;
6820             var delta = 0;
6821             if(e.wheelDelta){ /* IE/Opera. */
6822                 delta = e.wheelDelta/120;
6823             }else if(e.detail){ /* Mozilla case. */
6824                 delta = -e.detail/3;
6825             }
6826             return delta;
6827         },
6828
6829         /**
6830          * Returns true if the control, meta, shift or alt key was pressed during this event.
6831          * @return {Boolean}
6832          */
6833         hasModifier : function(){
6834             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6835         },
6836
6837         /**
6838          * Returns true if the target of this event equals el or is a child of el
6839          * @param {String/HTMLElement/Element} el
6840          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6841          * @return {Boolean}
6842          */
6843         within : function(el, related){
6844             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6845             return t && Roo.fly(el).contains(t);
6846         },
6847
6848         getPoint : function(){
6849             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6850         }
6851     };
6852
6853     return new Roo.EventObjectImpl();
6854 }();
6855             
6856     /*
6857  * Based on:
6858  * Ext JS Library 1.1.1
6859  * Copyright(c) 2006-2007, Ext JS, LLC.
6860  *
6861  * Originally Released Under LGPL - original licence link has changed is not relivant.
6862  *
6863  * Fork - LGPL
6864  * <script type="text/javascript">
6865  */
6866
6867  
6868 // was in Composite Element!??!?!
6869  
6870 (function(){
6871     var D = Roo.lib.Dom;
6872     var E = Roo.lib.Event;
6873     var A = Roo.lib.Anim;
6874
6875     // local style camelizing for speed
6876     var propCache = {};
6877     var camelRe = /(-[a-z])/gi;
6878     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6879     var view = document.defaultView;
6880
6881 /**
6882  * @class Roo.Element
6883  * Represents an Element in the DOM.<br><br>
6884  * Usage:<br>
6885 <pre><code>
6886 var el = Roo.get("my-div");
6887
6888 // or with getEl
6889 var el = getEl("my-div");
6890
6891 // or with a DOM element
6892 var el = Roo.get(myDivElement);
6893 </code></pre>
6894  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6895  * each call instead of constructing a new one.<br><br>
6896  * <b>Animations</b><br />
6897  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6898  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6899 <pre>
6900 Option    Default   Description
6901 --------- --------  ---------------------------------------------
6902 duration  .35       The duration of the animation in seconds
6903 easing    easeOut   The YUI easing method
6904 callback  none      A function to execute when the anim completes
6905 scope     this      The scope (this) of the callback function
6906 </pre>
6907 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6908 * manipulate the animation. Here's an example:
6909 <pre><code>
6910 var el = Roo.get("my-div");
6911
6912 // no animation
6913 el.setWidth(100);
6914
6915 // default animation
6916 el.setWidth(100, true);
6917
6918 // animation with some options set
6919 el.setWidth(100, {
6920     duration: 1,
6921     callback: this.foo,
6922     scope: this
6923 });
6924
6925 // using the "anim" property to get the Anim object
6926 var opt = {
6927     duration: 1,
6928     callback: this.foo,
6929     scope: this
6930 };
6931 el.setWidth(100, opt);
6932 ...
6933 if(opt.anim.isAnimated()){
6934     opt.anim.stop();
6935 }
6936 </code></pre>
6937 * <b> Composite (Collections of) Elements</b><br />
6938  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6939  * @constructor Create a new Element directly.
6940  * @param {String/HTMLElement} element
6941  * @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).
6942  */
6943     Roo.Element = function(element, forceNew){
6944         var dom = typeof element == "string" ?
6945                 document.getElementById(element) : element;
6946         if(!dom){ // invalid id/element
6947             return null;
6948         }
6949         var id = dom.id;
6950         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6951             return Roo.Element.cache[id];
6952         }
6953
6954         /**
6955          * The DOM element
6956          * @type HTMLElement
6957          */
6958         this.dom = dom;
6959
6960         /**
6961          * The DOM element ID
6962          * @type String
6963          */
6964         this.id = id || Roo.id(dom);
6965     };
6966
6967     var El = Roo.Element;
6968
6969     El.prototype = {
6970         /**
6971          * The element's default display mode  (defaults to "")
6972          * @type String
6973          */
6974         originalDisplay : "",
6975
6976         visibilityMode : 1,
6977         /**
6978          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6979          * @type String
6980          */
6981         defaultUnit : "px",
6982         /**
6983          * Sets the element's visibility mode. When setVisible() is called it
6984          * will use this to determine whether to set the visibility or the display property.
6985          * @param visMode Element.VISIBILITY or Element.DISPLAY
6986          * @return {Roo.Element} this
6987          */
6988         setVisibilityMode : function(visMode){
6989             this.visibilityMode = visMode;
6990             return this;
6991         },
6992         /**
6993          * Convenience method for setVisibilityMode(Element.DISPLAY)
6994          * @param {String} display (optional) What to set display to when visible
6995          * @return {Roo.Element} this
6996          */
6997         enableDisplayMode : function(display){
6998             this.setVisibilityMode(El.DISPLAY);
6999             if(typeof display != "undefined") this.originalDisplay = display;
7000             return this;
7001         },
7002
7003         /**
7004          * 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)
7005          * @param {String} selector The simple selector to test
7006          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7007                 search as a number or element (defaults to 10 || document.body)
7008          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7009          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7010          */
7011         findParent : function(simpleSelector, maxDepth, returnEl){
7012             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7013             maxDepth = maxDepth || 50;
7014             if(typeof maxDepth != "number"){
7015                 stopEl = Roo.getDom(maxDepth);
7016                 maxDepth = 10;
7017             }
7018             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7019                 if(dq.is(p, simpleSelector)){
7020                     return returnEl ? Roo.get(p) : p;
7021                 }
7022                 depth++;
7023                 p = p.parentNode;
7024             }
7025             return null;
7026         },
7027
7028
7029         /**
7030          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7031          * @param {String} selector The simple selector to test
7032          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7033                 search as a number or element (defaults to 10 || document.body)
7034          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7035          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7036          */
7037         findParentNode : function(simpleSelector, maxDepth, returnEl){
7038             var p = Roo.fly(this.dom.parentNode, '_internal');
7039             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7040         },
7041
7042         /**
7043          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7044          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7045          * @param {String} selector The simple selector to test
7046          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7047                 search as a number or element (defaults to 10 || document.body)
7048          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7049          */
7050         up : function(simpleSelector, maxDepth){
7051             return this.findParentNode(simpleSelector, maxDepth, true);
7052         },
7053
7054
7055
7056         /**
7057          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7058          * @param {String} selector The simple selector to test
7059          * @return {Boolean} True if this element matches the selector, else false
7060          */
7061         is : function(simpleSelector){
7062             return Roo.DomQuery.is(this.dom, simpleSelector);
7063         },
7064
7065         /**
7066          * Perform animation on this element.
7067          * @param {Object} args The YUI animation control args
7068          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7069          * @param {Function} onComplete (optional) Function to call when animation completes
7070          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7071          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7072          * @return {Roo.Element} this
7073          */
7074         animate : function(args, duration, onComplete, easing, animType){
7075             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7076             return this;
7077         },
7078
7079         /*
7080          * @private Internal animation call
7081          */
7082         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7083             animType = animType || 'run';
7084             opt = opt || {};
7085             var anim = Roo.lib.Anim[animType](
7086                 this.dom, args,
7087                 (opt.duration || defaultDur) || .35,
7088                 (opt.easing || defaultEase) || 'easeOut',
7089                 function(){
7090                     Roo.callback(cb, this);
7091                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7092                 },
7093                 this
7094             );
7095             opt.anim = anim;
7096             return anim;
7097         },
7098
7099         // private legacy anim prep
7100         preanim : function(a, i){
7101             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7102         },
7103
7104         /**
7105          * Removes worthless text nodes
7106          * @param {Boolean} forceReclean (optional) By default the element
7107          * keeps track if it has been cleaned already so
7108          * you can call this over and over. However, if you update the element and
7109          * need to force a reclean, you can pass true.
7110          */
7111         clean : function(forceReclean){
7112             if(this.isCleaned && forceReclean !== true){
7113                 return this;
7114             }
7115             var ns = /\S/;
7116             var d = this.dom, n = d.firstChild, ni = -1;
7117             while(n){
7118                 var nx = n.nextSibling;
7119                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7120                     d.removeChild(n);
7121                 }else{
7122                     n.nodeIndex = ++ni;
7123                 }
7124                 n = nx;
7125             }
7126             this.isCleaned = true;
7127             return this;
7128         },
7129
7130         // private
7131         calcOffsetsTo : function(el){
7132             el = Roo.get(el);
7133             var d = el.dom;
7134             var restorePos = false;
7135             if(el.getStyle('position') == 'static'){
7136                 el.position('relative');
7137                 restorePos = true;
7138             }
7139             var x = 0, y =0;
7140             var op = this.dom;
7141             while(op && op != d && op.tagName != 'HTML'){
7142                 x+= op.offsetLeft;
7143                 y+= op.offsetTop;
7144                 op = op.offsetParent;
7145             }
7146             if(restorePos){
7147                 el.position('static');
7148             }
7149             return [x, y];
7150         },
7151
7152         /**
7153          * Scrolls this element into view within the passed container.
7154          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7155          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7156          * @return {Roo.Element} this
7157          */
7158         scrollIntoView : function(container, hscroll){
7159             var c = Roo.getDom(container) || document.body;
7160             var el = this.dom;
7161
7162             var o = this.calcOffsetsTo(c),
7163                 l = o[0],
7164                 t = o[1],
7165                 b = t+el.offsetHeight,
7166                 r = l+el.offsetWidth;
7167
7168             var ch = c.clientHeight;
7169             var ct = parseInt(c.scrollTop, 10);
7170             var cl = parseInt(c.scrollLeft, 10);
7171             var cb = ct + ch;
7172             var cr = cl + c.clientWidth;
7173
7174             if(t < ct){
7175                 c.scrollTop = t;
7176             }else if(b > cb){
7177                 c.scrollTop = b-ch;
7178             }
7179
7180             if(hscroll !== false){
7181                 if(l < cl){
7182                     c.scrollLeft = l;
7183                 }else if(r > cr){
7184                     c.scrollLeft = r-c.clientWidth;
7185                 }
7186             }
7187             return this;
7188         },
7189
7190         // private
7191         scrollChildIntoView : function(child, hscroll){
7192             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7193         },
7194
7195         /**
7196          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7197          * the new height may not be available immediately.
7198          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7199          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7200          * @param {Function} onComplete (optional) Function to call when animation completes
7201          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7202          * @return {Roo.Element} this
7203          */
7204         autoHeight : function(animate, duration, onComplete, easing){
7205             var oldHeight = this.getHeight();
7206             this.clip();
7207             this.setHeight(1); // force clipping
7208             setTimeout(function(){
7209                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7210                 if(!animate){
7211                     this.setHeight(height);
7212                     this.unclip();
7213                     if(typeof onComplete == "function"){
7214                         onComplete();
7215                     }
7216                 }else{
7217                     this.setHeight(oldHeight); // restore original height
7218                     this.setHeight(height, animate, duration, function(){
7219                         this.unclip();
7220                         if(typeof onComplete == "function") onComplete();
7221                     }.createDelegate(this), easing);
7222                 }
7223             }.createDelegate(this), 0);
7224             return this;
7225         },
7226
7227         /**
7228          * Returns true if this element is an ancestor of the passed element
7229          * @param {HTMLElement/String} el The element to check
7230          * @return {Boolean} True if this element is an ancestor of el, else false
7231          */
7232         contains : function(el){
7233             if(!el){return false;}
7234             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7235         },
7236
7237         /**
7238          * Checks whether the element is currently visible using both visibility and display properties.
7239          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7240          * @return {Boolean} True if the element is currently visible, else false
7241          */
7242         isVisible : function(deep) {
7243             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7244             if(deep !== true || !vis){
7245                 return vis;
7246             }
7247             var p = this.dom.parentNode;
7248             while(p && p.tagName.toLowerCase() != "body"){
7249                 if(!Roo.fly(p, '_isVisible').isVisible()){
7250                     return false;
7251                 }
7252                 p = p.parentNode;
7253             }
7254             return true;
7255         },
7256
7257         /**
7258          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7259          * @param {String} selector The CSS selector
7260          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7261          * @return {CompositeElement/CompositeElementLite} The composite element
7262          */
7263         select : function(selector, unique){
7264             return El.select(selector, unique, this.dom);
7265         },
7266
7267         /**
7268          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7269          * @param {String} selector The CSS selector
7270          * @return {Array} An array of the matched nodes
7271          */
7272         query : function(selector, unique){
7273             return Roo.DomQuery.select(selector, this.dom);
7274         },
7275
7276         /**
7277          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7278          * @param {String} selector The CSS selector
7279          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7280          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7281          */
7282         child : function(selector, returnDom){
7283             var n = Roo.DomQuery.selectNode(selector, this.dom);
7284             return returnDom ? n : Roo.get(n);
7285         },
7286
7287         /**
7288          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7289          * @param {String} selector The CSS selector
7290          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7291          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7292          */
7293         down : function(selector, returnDom){
7294             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7295             return returnDom ? n : Roo.get(n);
7296         },
7297
7298         /**
7299          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7300          * @param {String} group The group the DD object is member of
7301          * @param {Object} config The DD config object
7302          * @param {Object} overrides An object containing methods to override/implement on the DD object
7303          * @return {Roo.dd.DD} The DD object
7304          */
7305         initDD : function(group, config, overrides){
7306             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7307             return Roo.apply(dd, overrides);
7308         },
7309
7310         /**
7311          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7312          * @param {String} group The group the DDProxy object is member of
7313          * @param {Object} config The DDProxy config object
7314          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7315          * @return {Roo.dd.DDProxy} The DDProxy object
7316          */
7317         initDDProxy : function(group, config, overrides){
7318             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7319             return Roo.apply(dd, overrides);
7320         },
7321
7322         /**
7323          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7324          * @param {String} group The group the DDTarget object is member of
7325          * @param {Object} config The DDTarget config object
7326          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7327          * @return {Roo.dd.DDTarget} The DDTarget object
7328          */
7329         initDDTarget : function(group, config, overrides){
7330             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7331             return Roo.apply(dd, overrides);
7332         },
7333
7334         /**
7335          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7336          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7337          * @param {Boolean} visible Whether the element is visible
7338          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7339          * @return {Roo.Element} this
7340          */
7341          setVisible : function(visible, animate){
7342             if(!animate || !A){
7343                 if(this.visibilityMode == El.DISPLAY){
7344                     this.setDisplayed(visible);
7345                 }else{
7346                     this.fixDisplay();
7347                     this.dom.style.visibility = visible ? "visible" : "hidden";
7348                 }
7349             }else{
7350                 // closure for composites
7351                 var dom = this.dom;
7352                 var visMode = this.visibilityMode;
7353                 if(visible){
7354                     this.setOpacity(.01);
7355                     this.setVisible(true);
7356                 }
7357                 this.anim({opacity: { to: (visible?1:0) }},
7358                       this.preanim(arguments, 1),
7359                       null, .35, 'easeIn', function(){
7360                          if(!visible){
7361                              if(visMode == El.DISPLAY){
7362                                  dom.style.display = "none";
7363                              }else{
7364                                  dom.style.visibility = "hidden";
7365                              }
7366                              Roo.get(dom).setOpacity(1);
7367                          }
7368                      });
7369             }
7370             return this;
7371         },
7372
7373         /**
7374          * Returns true if display is not "none"
7375          * @return {Boolean}
7376          */
7377         isDisplayed : function() {
7378             return this.getStyle("display") != "none";
7379         },
7380
7381         /**
7382          * Toggles the element's visibility or display, depending on visibility mode.
7383          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7384          * @return {Roo.Element} this
7385          */
7386         toggle : function(animate){
7387             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7388             return this;
7389         },
7390
7391         /**
7392          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7393          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7394          * @return {Roo.Element} this
7395          */
7396         setDisplayed : function(value) {
7397             if(typeof value == "boolean"){
7398                value = value ? this.originalDisplay : "none";
7399             }
7400             this.setStyle("display", value);
7401             return this;
7402         },
7403
7404         /**
7405          * Tries to focus the element. Any exceptions are caught and ignored.
7406          * @return {Roo.Element} this
7407          */
7408         focus : function() {
7409             try{
7410                 this.dom.focus();
7411             }catch(e){}
7412             return this;
7413         },
7414
7415         /**
7416          * Tries to blur the element. Any exceptions are caught and ignored.
7417          * @return {Roo.Element} this
7418          */
7419         blur : function() {
7420             try{
7421                 this.dom.blur();
7422             }catch(e){}
7423             return this;
7424         },
7425
7426         /**
7427          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7428          * @param {String/Array} className The CSS class to add, or an array of classes
7429          * @return {Roo.Element} this
7430          */
7431         addClass : function(className){
7432             if(className instanceof Array){
7433                 for(var i = 0, len = className.length; i < len; i++) {
7434                     this.addClass(className[i]);
7435                 }
7436             }else{
7437                 if(className && !this.hasClass(className)){
7438                     this.dom.className = this.dom.className + " " + className;
7439                 }
7440             }
7441             return this;
7442         },
7443
7444         /**
7445          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7446          * @param {String/Array} className The CSS class to add, or an array of classes
7447          * @return {Roo.Element} this
7448          */
7449         radioClass : function(className){
7450             var siblings = this.dom.parentNode.childNodes;
7451             for(var i = 0; i < siblings.length; i++) {
7452                 var s = siblings[i];
7453                 if(s.nodeType == 1){
7454                     Roo.get(s).removeClass(className);
7455                 }
7456             }
7457             this.addClass(className);
7458             return this;
7459         },
7460
7461         /**
7462          * Removes one or more CSS classes from the element.
7463          * @param {String/Array} className The CSS class to remove, or an array of classes
7464          * @return {Roo.Element} this
7465          */
7466         removeClass : function(className){
7467             if(!className || !this.dom.className){
7468                 return this;
7469             }
7470             if(className instanceof Array){
7471                 for(var i = 0, len = className.length; i < len; i++) {
7472                     this.removeClass(className[i]);
7473                 }
7474             }else{
7475                 if(this.hasClass(className)){
7476                     var re = this.classReCache[className];
7477                     if (!re) {
7478                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7479                        this.classReCache[className] = re;
7480                     }
7481                     this.dom.className =
7482                         this.dom.className.replace(re, " ");
7483                 }
7484             }
7485             return this;
7486         },
7487
7488         // private
7489         classReCache: {},
7490
7491         /**
7492          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7493          * @param {String} className The CSS class to toggle
7494          * @return {Roo.Element} this
7495          */
7496         toggleClass : function(className){
7497             if(this.hasClass(className)){
7498                 this.removeClass(className);
7499             }else{
7500                 this.addClass(className);
7501             }
7502             return this;
7503         },
7504
7505         /**
7506          * Checks if the specified CSS class exists on this element's DOM node.
7507          * @param {String} className The CSS class to check for
7508          * @return {Boolean} True if the class exists, else false
7509          */
7510         hasClass : function(className){
7511             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7512         },
7513
7514         /**
7515          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7516          * @param {String} oldClassName The CSS class to replace
7517          * @param {String} newClassName The replacement CSS class
7518          * @return {Roo.Element} this
7519          */
7520         replaceClass : function(oldClassName, newClassName){
7521             this.removeClass(oldClassName);
7522             this.addClass(newClassName);
7523             return this;
7524         },
7525
7526         /**
7527          * Returns an object with properties matching the styles requested.
7528          * For example, el.getStyles('color', 'font-size', 'width') might return
7529          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7530          * @param {String} style1 A style name
7531          * @param {String} style2 A style name
7532          * @param {String} etc.
7533          * @return {Object} The style object
7534          */
7535         getStyles : function(){
7536             var a = arguments, len = a.length, r = {};
7537             for(var i = 0; i < len; i++){
7538                 r[a[i]] = this.getStyle(a[i]);
7539             }
7540             return r;
7541         },
7542
7543         /**
7544          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7545          * @param {String} property The style property whose value is returned.
7546          * @return {String} The current value of the style property for this element.
7547          */
7548         getStyle : function(){
7549             return view && view.getComputedStyle ?
7550                 function(prop){
7551                     var el = this.dom, v, cs, camel;
7552                     if(prop == 'float'){
7553                         prop = "cssFloat";
7554                     }
7555                     if(el.style && (v = el.style[prop])){
7556                         return v;
7557                     }
7558                     if(cs = view.getComputedStyle(el, "")){
7559                         if(!(camel = propCache[prop])){
7560                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7561                         }
7562                         return cs[camel];
7563                     }
7564                     return null;
7565                 } :
7566                 function(prop){
7567                     var el = this.dom, v, cs, camel;
7568                     if(prop == 'opacity'){
7569                         if(typeof el.style.filter == 'string'){
7570                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7571                             if(m){
7572                                 var fv = parseFloat(m[1]);
7573                                 if(!isNaN(fv)){
7574                                     return fv ? fv / 100 : 0;
7575                                 }
7576                             }
7577                         }
7578                         return 1;
7579                     }else if(prop == 'float'){
7580                         prop = "styleFloat";
7581                     }
7582                     if(!(camel = propCache[prop])){
7583                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7584                     }
7585                     if(v = el.style[camel]){
7586                         return v;
7587                     }
7588                     if(cs = el.currentStyle){
7589                         return cs[camel];
7590                     }
7591                     return null;
7592                 };
7593         }(),
7594
7595         /**
7596          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7597          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7598          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7599          * @return {Roo.Element} this
7600          */
7601         setStyle : function(prop, value){
7602             if(typeof prop == "string"){
7603                 
7604                 if (prop == 'float') {
7605                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7606                     return this;
7607                 }
7608                 
7609                 var camel;
7610                 if(!(camel = propCache[prop])){
7611                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7612                 }
7613                 
7614                 if(camel == 'opacity') {
7615                     this.setOpacity(value);
7616                 }else{
7617                     this.dom.style[camel] = value;
7618                 }
7619             }else{
7620                 for(var style in prop){
7621                     if(typeof prop[style] != "function"){
7622                        this.setStyle(style, prop[style]);
7623                     }
7624                 }
7625             }
7626             return this;
7627         },
7628
7629         /**
7630          * More flexible version of {@link #setStyle} for setting style properties.
7631          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7632          * a function which returns such a specification.
7633          * @return {Roo.Element} this
7634          */
7635         applyStyles : function(style){
7636             Roo.DomHelper.applyStyles(this.dom, style);
7637             return this;
7638         },
7639
7640         /**
7641           * 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).
7642           * @return {Number} The X position of the element
7643           */
7644         getX : function(){
7645             return D.getX(this.dom);
7646         },
7647
7648         /**
7649           * 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).
7650           * @return {Number} The Y position of the element
7651           */
7652         getY : function(){
7653             return D.getY(this.dom);
7654         },
7655
7656         /**
7657           * 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).
7658           * @return {Array} The XY position of the element
7659           */
7660         getXY : function(){
7661             return D.getXY(this.dom);
7662         },
7663
7664         /**
7665          * 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).
7666          * @param {Number} The X position of the element
7667          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7668          * @return {Roo.Element} this
7669          */
7670         setX : function(x, animate){
7671             if(!animate || !A){
7672                 D.setX(this.dom, x);
7673             }else{
7674                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7675             }
7676             return this;
7677         },
7678
7679         /**
7680          * 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).
7681          * @param {Number} The Y position of the element
7682          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7683          * @return {Roo.Element} this
7684          */
7685         setY : function(y, animate){
7686             if(!animate || !A){
7687                 D.setY(this.dom, y);
7688             }else{
7689                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7690             }
7691             return this;
7692         },
7693
7694         /**
7695          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7696          * @param {String} left The left CSS property value
7697          * @return {Roo.Element} this
7698          */
7699         setLeft : function(left){
7700             this.setStyle("left", this.addUnits(left));
7701             return this;
7702         },
7703
7704         /**
7705          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7706          * @param {String} top The top CSS property value
7707          * @return {Roo.Element} this
7708          */
7709         setTop : function(top){
7710             this.setStyle("top", this.addUnits(top));
7711             return this;
7712         },
7713
7714         /**
7715          * Sets the element's CSS right style.
7716          * @param {String} right The right CSS property value
7717          * @return {Roo.Element} this
7718          */
7719         setRight : function(right){
7720             this.setStyle("right", this.addUnits(right));
7721             return this;
7722         },
7723
7724         /**
7725          * Sets the element's CSS bottom style.
7726          * @param {String} bottom The bottom CSS property value
7727          * @return {Roo.Element} this
7728          */
7729         setBottom : function(bottom){
7730             this.setStyle("bottom", this.addUnits(bottom));
7731             return this;
7732         },
7733
7734         /**
7735          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7736          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7737          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7738          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7739          * @return {Roo.Element} this
7740          */
7741         setXY : function(pos, animate){
7742             if(!animate || !A){
7743                 D.setXY(this.dom, pos);
7744             }else{
7745                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7746             }
7747             return this;
7748         },
7749
7750         /**
7751          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7752          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7753          * @param {Number} x X value for new position (coordinates are page-based)
7754          * @param {Number} y Y value for new position (coordinates are page-based)
7755          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7756          * @return {Roo.Element} this
7757          */
7758         setLocation : function(x, y, animate){
7759             this.setXY([x, y], this.preanim(arguments, 2));
7760             return this;
7761         },
7762
7763         /**
7764          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7765          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7766          * @param {Number} x X value for new position (coordinates are page-based)
7767          * @param {Number} y Y value for new position (coordinates are page-based)
7768          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7769          * @return {Roo.Element} this
7770          */
7771         moveTo : function(x, y, animate){
7772             this.setXY([x, y], this.preanim(arguments, 2));
7773             return this;
7774         },
7775
7776         /**
7777          * Returns the region of the given element.
7778          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7779          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7780          */
7781         getRegion : function(){
7782             return D.getRegion(this.dom);
7783         },
7784
7785         /**
7786          * Returns the offset height of the element
7787          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7788          * @return {Number} The element's height
7789          */
7790         getHeight : function(contentHeight){
7791             var h = this.dom.offsetHeight || 0;
7792             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7793         },
7794
7795         /**
7796          * Returns the offset width of the element
7797          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7798          * @return {Number} The element's width
7799          */
7800         getWidth : function(contentWidth){
7801             var w = this.dom.offsetWidth || 0;
7802             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7803         },
7804
7805         /**
7806          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7807          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7808          * if a height has not been set using CSS.
7809          * @return {Number}
7810          */
7811         getComputedHeight : function(){
7812             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7813             if(!h){
7814                 h = parseInt(this.getStyle('height'), 10) || 0;
7815                 if(!this.isBorderBox()){
7816                     h += this.getFrameWidth('tb');
7817                 }
7818             }
7819             return h;
7820         },
7821
7822         /**
7823          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7824          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7825          * if a width has not been set using CSS.
7826          * @return {Number}
7827          */
7828         getComputedWidth : function(){
7829             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7830             if(!w){
7831                 w = parseInt(this.getStyle('width'), 10) || 0;
7832                 if(!this.isBorderBox()){
7833                     w += this.getFrameWidth('lr');
7834                 }
7835             }
7836             return w;
7837         },
7838
7839         /**
7840          * Returns the size of the element.
7841          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7842          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7843          */
7844         getSize : function(contentSize){
7845             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7846         },
7847
7848         /**
7849          * Returns the width and height of the viewport.
7850          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7851          */
7852         getViewSize : function(){
7853             var d = this.dom, doc = document, aw = 0, ah = 0;
7854             if(d == doc || d == doc.body){
7855                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7856             }else{
7857                 return {
7858                     width : d.clientWidth,
7859                     height: d.clientHeight
7860                 };
7861             }
7862         },
7863
7864         /**
7865          * Returns the value of the "value" attribute
7866          * @param {Boolean} asNumber true to parse the value as a number
7867          * @return {String/Number}
7868          */
7869         getValue : function(asNumber){
7870             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7871         },
7872
7873         // private
7874         adjustWidth : function(width){
7875             if(typeof width == "number"){
7876                 if(this.autoBoxAdjust && !this.isBorderBox()){
7877                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7878                 }
7879                 if(width < 0){
7880                     width = 0;
7881                 }
7882             }
7883             return width;
7884         },
7885
7886         // private
7887         adjustHeight : function(height){
7888             if(typeof height == "number"){
7889                if(this.autoBoxAdjust && !this.isBorderBox()){
7890                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7891                }
7892                if(height < 0){
7893                    height = 0;
7894                }
7895             }
7896             return height;
7897         },
7898
7899         /**
7900          * Set the width of the element
7901          * @param {Number} width The new width
7902          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7903          * @return {Roo.Element} this
7904          */
7905         setWidth : function(width, animate){
7906             width = this.adjustWidth(width);
7907             if(!animate || !A){
7908                 this.dom.style.width = this.addUnits(width);
7909             }else{
7910                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7911             }
7912             return this;
7913         },
7914
7915         /**
7916          * Set the height of the element
7917          * @param {Number} height The new height
7918          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7919          * @return {Roo.Element} this
7920          */
7921          setHeight : function(height, animate){
7922             height = this.adjustHeight(height);
7923             if(!animate || !A){
7924                 this.dom.style.height = this.addUnits(height);
7925             }else{
7926                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7927             }
7928             return this;
7929         },
7930
7931         /**
7932          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7933          * @param {Number} width The new width
7934          * @param {Number} height The new height
7935          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7936          * @return {Roo.Element} this
7937          */
7938          setSize : function(width, height, animate){
7939             if(typeof width == "object"){ // in case of object from getSize()
7940                 height = width.height; width = width.width;
7941             }
7942             width = this.adjustWidth(width); height = this.adjustHeight(height);
7943             if(!animate || !A){
7944                 this.dom.style.width = this.addUnits(width);
7945                 this.dom.style.height = this.addUnits(height);
7946             }else{
7947                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7948             }
7949             return this;
7950         },
7951
7952         /**
7953          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7954          * @param {Number} x X value for new position (coordinates are page-based)
7955          * @param {Number} y Y value for new position (coordinates are page-based)
7956          * @param {Number} width The new width
7957          * @param {Number} height The new height
7958          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7959          * @return {Roo.Element} this
7960          */
7961         setBounds : function(x, y, width, height, animate){
7962             if(!animate || !A){
7963                 this.setSize(width, height);
7964                 this.setLocation(x, y);
7965             }else{
7966                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7967                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7968                               this.preanim(arguments, 4), 'motion');
7969             }
7970             return this;
7971         },
7972
7973         /**
7974          * 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.
7975          * @param {Roo.lib.Region} region The region to fill
7976          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977          * @return {Roo.Element} this
7978          */
7979         setRegion : function(region, animate){
7980             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7981             return this;
7982         },
7983
7984         /**
7985          * Appends an event handler
7986          *
7987          * @param {String}   eventName     The type of event to append
7988          * @param {Function} fn        The method the event invokes
7989          * @param {Object} scope       (optional) The scope (this object) of the fn
7990          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7991          */
7992         addListener : function(eventName, fn, scope, options){
7993             if (this.dom) {
7994                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7995             }
7996         },
7997
7998         /**
7999          * Removes an event handler from this element
8000          * @param {String} eventName the type of event to remove
8001          * @param {Function} fn the method the event invokes
8002          * @return {Roo.Element} this
8003          */
8004         removeListener : function(eventName, fn){
8005             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8006             return this;
8007         },
8008
8009         /**
8010          * Removes all previous added listeners from this element
8011          * @return {Roo.Element} this
8012          */
8013         removeAllListeners : function(){
8014             E.purgeElement(this.dom);
8015             return this;
8016         },
8017
8018         relayEvent : function(eventName, observable){
8019             this.on(eventName, function(e){
8020                 observable.fireEvent(eventName, e);
8021             });
8022         },
8023
8024         /**
8025          * Set the opacity of the element
8026          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8027          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8028          * @return {Roo.Element} this
8029          */
8030          setOpacity : function(opacity, animate){
8031             if(!animate || !A){
8032                 var s = this.dom.style;
8033                 if(Roo.isIE){
8034                     s.zoom = 1;
8035                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8036                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8037                 }else{
8038                     s.opacity = opacity;
8039                 }
8040             }else{
8041                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8042             }
8043             return this;
8044         },
8045
8046         /**
8047          * Gets the left X coordinate
8048          * @param {Boolean} local True to get the local css position instead of page coordinate
8049          * @return {Number}
8050          */
8051         getLeft : function(local){
8052             if(!local){
8053                 return this.getX();
8054             }else{
8055                 return parseInt(this.getStyle("left"), 10) || 0;
8056             }
8057         },
8058
8059         /**
8060          * Gets the right X coordinate of the element (element X position + element width)
8061          * @param {Boolean} local True to get the local css position instead of page coordinate
8062          * @return {Number}
8063          */
8064         getRight : function(local){
8065             if(!local){
8066                 return this.getX() + this.getWidth();
8067             }else{
8068                 return (this.getLeft(true) + this.getWidth()) || 0;
8069             }
8070         },
8071
8072         /**
8073          * Gets the top Y coordinate
8074          * @param {Boolean} local True to get the local css position instead of page coordinate
8075          * @return {Number}
8076          */
8077         getTop : function(local) {
8078             if(!local){
8079                 return this.getY();
8080             }else{
8081                 return parseInt(this.getStyle("top"), 10) || 0;
8082             }
8083         },
8084
8085         /**
8086          * Gets the bottom Y coordinate of the element (element Y position + element height)
8087          * @param {Boolean} local True to get the local css position instead of page coordinate
8088          * @return {Number}
8089          */
8090         getBottom : function(local){
8091             if(!local){
8092                 return this.getY() + this.getHeight();
8093             }else{
8094                 return (this.getTop(true) + this.getHeight()) || 0;
8095             }
8096         },
8097
8098         /**
8099         * Initializes positioning on this element. If a desired position is not passed, it will make the
8100         * the element positioned relative IF it is not already positioned.
8101         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8102         * @param {Number} zIndex (optional) The zIndex to apply
8103         * @param {Number} x (optional) Set the page X position
8104         * @param {Number} y (optional) Set the page Y position
8105         */
8106         position : function(pos, zIndex, x, y){
8107             if(!pos){
8108                if(this.getStyle('position') == 'static'){
8109                    this.setStyle('position', 'relative');
8110                }
8111             }else{
8112                 this.setStyle("position", pos);
8113             }
8114             if(zIndex){
8115                 this.setStyle("z-index", zIndex);
8116             }
8117             if(x !== undefined && y !== undefined){
8118                 this.setXY([x, y]);
8119             }else if(x !== undefined){
8120                 this.setX(x);
8121             }else if(y !== undefined){
8122                 this.setY(y);
8123             }
8124         },
8125
8126         /**
8127         * Clear positioning back to the default when the document was loaded
8128         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8129         * @return {Roo.Element} this
8130          */
8131         clearPositioning : function(value){
8132             value = value ||'';
8133             this.setStyle({
8134                 "left": value,
8135                 "right": value,
8136                 "top": value,
8137                 "bottom": value,
8138                 "z-index": "",
8139                 "position" : "static"
8140             });
8141             return this;
8142         },
8143
8144         /**
8145         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8146         * snapshot before performing an update and then restoring the element.
8147         * @return {Object}
8148         */
8149         getPositioning : function(){
8150             var l = this.getStyle("left");
8151             var t = this.getStyle("top");
8152             return {
8153                 "position" : this.getStyle("position"),
8154                 "left" : l,
8155                 "right" : l ? "" : this.getStyle("right"),
8156                 "top" : t,
8157                 "bottom" : t ? "" : this.getStyle("bottom"),
8158                 "z-index" : this.getStyle("z-index")
8159             };
8160         },
8161
8162         /**
8163          * Gets the width of the border(s) for the specified side(s)
8164          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8165          * passing lr would get the border (l)eft width + the border (r)ight width.
8166          * @return {Number} The width of the sides passed added together
8167          */
8168         getBorderWidth : function(side){
8169             return this.addStyles(side, El.borders);
8170         },
8171
8172         /**
8173          * Gets the width of the padding(s) for the specified side(s)
8174          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8175          * passing lr would get the padding (l)eft + the padding (r)ight.
8176          * @return {Number} The padding of the sides passed added together
8177          */
8178         getPadding : function(side){
8179             return this.addStyles(side, El.paddings);
8180         },
8181
8182         /**
8183         * Set positioning with an object returned by getPositioning().
8184         * @param {Object} posCfg
8185         * @return {Roo.Element} this
8186          */
8187         setPositioning : function(pc){
8188             this.applyStyles(pc);
8189             if(pc.right == "auto"){
8190                 this.dom.style.right = "";
8191             }
8192             if(pc.bottom == "auto"){
8193                 this.dom.style.bottom = "";
8194             }
8195             return this;
8196         },
8197
8198         // private
8199         fixDisplay : function(){
8200             if(this.getStyle("display") == "none"){
8201                 this.setStyle("visibility", "hidden");
8202                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8203                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8204                     this.setStyle("display", "block");
8205                 }
8206             }
8207         },
8208
8209         /**
8210          * Quick set left and top adding default units
8211          * @param {String} left The left CSS property value
8212          * @param {String} top The top CSS property value
8213          * @return {Roo.Element} this
8214          */
8215          setLeftTop : function(left, top){
8216             this.dom.style.left = this.addUnits(left);
8217             this.dom.style.top = this.addUnits(top);
8218             return this;
8219         },
8220
8221         /**
8222          * Move this element relative to its current position.
8223          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8224          * @param {Number} distance How far to move the element in pixels
8225          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8226          * @return {Roo.Element} this
8227          */
8228          move : function(direction, distance, animate){
8229             var xy = this.getXY();
8230             direction = direction.toLowerCase();
8231             switch(direction){
8232                 case "l":
8233                 case "left":
8234                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8235                     break;
8236                case "r":
8237                case "right":
8238                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8239                     break;
8240                case "t":
8241                case "top":
8242                case "up":
8243                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8244                     break;
8245                case "b":
8246                case "bottom":
8247                case "down":
8248                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8249                     break;
8250             }
8251             return this;
8252         },
8253
8254         /**
8255          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8256          * @return {Roo.Element} this
8257          */
8258         clip : function(){
8259             if(!this.isClipped){
8260                this.isClipped = true;
8261                this.originalClip = {
8262                    "o": this.getStyle("overflow"),
8263                    "x": this.getStyle("overflow-x"),
8264                    "y": this.getStyle("overflow-y")
8265                };
8266                this.setStyle("overflow", "hidden");
8267                this.setStyle("overflow-x", "hidden");
8268                this.setStyle("overflow-y", "hidden");
8269             }
8270             return this;
8271         },
8272
8273         /**
8274          *  Return clipping (overflow) to original clipping before clip() was called
8275          * @return {Roo.Element} this
8276          */
8277         unclip : function(){
8278             if(this.isClipped){
8279                 this.isClipped = false;
8280                 var o = this.originalClip;
8281                 if(o.o){this.setStyle("overflow", o.o);}
8282                 if(o.x){this.setStyle("overflow-x", o.x);}
8283                 if(o.y){this.setStyle("overflow-y", o.y);}
8284             }
8285             return this;
8286         },
8287
8288
8289         /**
8290          * Gets the x,y coordinates specified by the anchor position on the element.
8291          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8292          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8293          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8294          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8295          * @return {Array} [x, y] An array containing the element's x and y coordinates
8296          */
8297         getAnchorXY : function(anchor, local, s){
8298             //Passing a different size is useful for pre-calculating anchors,
8299             //especially for anchored animations that change the el size.
8300
8301             var w, h, vp = false;
8302             if(!s){
8303                 var d = this.dom;
8304                 if(d == document.body || d == document){
8305                     vp = true;
8306                     w = D.getViewWidth(); h = D.getViewHeight();
8307                 }else{
8308                     w = this.getWidth(); h = this.getHeight();
8309                 }
8310             }else{
8311                 w = s.width;  h = s.height;
8312             }
8313             var x = 0, y = 0, r = Math.round;
8314             switch((anchor || "tl").toLowerCase()){
8315                 case "c":
8316                     x = r(w*.5);
8317                     y = r(h*.5);
8318                 break;
8319                 case "t":
8320                     x = r(w*.5);
8321                     y = 0;
8322                 break;
8323                 case "l":
8324                     x = 0;
8325                     y = r(h*.5);
8326                 break;
8327                 case "r":
8328                     x = w;
8329                     y = r(h*.5);
8330                 break;
8331                 case "b":
8332                     x = r(w*.5);
8333                     y = h;
8334                 break;
8335                 case "tl":
8336                     x = 0;
8337                     y = 0;
8338                 break;
8339                 case "bl":
8340                     x = 0;
8341                     y = h;
8342                 break;
8343                 case "br":
8344                     x = w;
8345                     y = h;
8346                 break;
8347                 case "tr":
8348                     x = w;
8349                     y = 0;
8350                 break;
8351             }
8352             if(local === true){
8353                 return [x, y];
8354             }
8355             if(vp){
8356                 var sc = this.getScroll();
8357                 return [x + sc.left, y + sc.top];
8358             }
8359             //Add the element's offset xy
8360             var o = this.getXY();
8361             return [x+o[0], y+o[1]];
8362         },
8363
8364         /**
8365          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8366          * supported position values.
8367          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8368          * @param {String} position The position to align to.
8369          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8370          * @return {Array} [x, y]
8371          */
8372         getAlignToXY : function(el, p, o){
8373             el = Roo.get(el);
8374             var d = this.dom;
8375             if(!el.dom){
8376                 throw "Element.alignTo with an element that doesn't exist";
8377             }
8378             var c = false; //constrain to viewport
8379             var p1 = "", p2 = "";
8380             o = o || [0,0];
8381
8382             if(!p){
8383                 p = "tl-bl";
8384             }else if(p == "?"){
8385                 p = "tl-bl?";
8386             }else if(p.indexOf("-") == -1){
8387                 p = "tl-" + p;
8388             }
8389             p = p.toLowerCase();
8390             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8391             if(!m){
8392                throw "Element.alignTo with an invalid alignment " + p;
8393             }
8394             p1 = m[1]; p2 = m[2]; c = !!m[3];
8395
8396             //Subtract the aligned el's internal xy from the target's offset xy
8397             //plus custom offset to get the aligned el's new offset xy
8398             var a1 = this.getAnchorXY(p1, true);
8399             var a2 = el.getAnchorXY(p2, false);
8400             var x = a2[0] - a1[0] + o[0];
8401             var y = a2[1] - a1[1] + o[1];
8402             if(c){
8403                 //constrain the aligned el to viewport if necessary
8404                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8405                 // 5px of margin for ie
8406                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8407
8408                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8409                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8410                 //otherwise swap the aligned el to the opposite border of the target.
8411                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8412                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8413                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8414                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8415
8416                var doc = document;
8417                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8418                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8419
8420                if((x+w) > dw + scrollX){
8421                     x = swapX ? r.left-w : dw+scrollX-w;
8422                 }
8423                if(x < scrollX){
8424                    x = swapX ? r.right : scrollX;
8425                }
8426                if((y+h) > dh + scrollY){
8427                     y = swapY ? r.top-h : dh+scrollY-h;
8428                 }
8429                if (y < scrollY){
8430                    y = swapY ? r.bottom : scrollY;
8431                }
8432             }
8433             return [x,y];
8434         },
8435
8436         // private
8437         getConstrainToXY : function(){
8438             var os = {top:0, left:0, bottom:0, right: 0};
8439
8440             return function(el, local, offsets, proposedXY){
8441                 el = Roo.get(el);
8442                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8443
8444                 var vw, vh, vx = 0, vy = 0;
8445                 if(el.dom == document.body || el.dom == document){
8446                     vw = Roo.lib.Dom.getViewWidth();
8447                     vh = Roo.lib.Dom.getViewHeight();
8448                 }else{
8449                     vw = el.dom.clientWidth;
8450                     vh = el.dom.clientHeight;
8451                     if(!local){
8452                         var vxy = el.getXY();
8453                         vx = vxy[0];
8454                         vy = vxy[1];
8455                     }
8456                 }
8457
8458                 var s = el.getScroll();
8459
8460                 vx += offsets.left + s.left;
8461                 vy += offsets.top + s.top;
8462
8463                 vw -= offsets.right;
8464                 vh -= offsets.bottom;
8465
8466                 var vr = vx+vw;
8467                 var vb = vy+vh;
8468
8469                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8470                 var x = xy[0], y = xy[1];
8471                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8472
8473                 // only move it if it needs it
8474                 var moved = false;
8475
8476                 // first validate right/bottom
8477                 if((x + w) > vr){
8478                     x = vr - w;
8479                     moved = true;
8480                 }
8481                 if((y + h) > vb){
8482                     y = vb - h;
8483                     moved = true;
8484                 }
8485                 // then make sure top/left isn't negative
8486                 if(x < vx){
8487                     x = vx;
8488                     moved = true;
8489                 }
8490                 if(y < vy){
8491                     y = vy;
8492                     moved = true;
8493                 }
8494                 return moved ? [x, y] : false;
8495             };
8496         }(),
8497
8498         // private
8499         adjustForConstraints : function(xy, parent, offsets){
8500             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8501         },
8502
8503         /**
8504          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8505          * document it aligns it to the viewport.
8506          * The position parameter is optional, and can be specified in any one of the following formats:
8507          * <ul>
8508          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8509          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8510          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8511          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8512          *   <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
8513          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8514          * </ul>
8515          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8516          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8517          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8518          * that specified in order to enforce the viewport constraints.
8519          * Following are all of the supported anchor positions:
8520     <pre>
8521     Value  Description
8522     -----  -----------------------------
8523     tl     The top left corner (default)
8524     t      The center of the top edge
8525     tr     The top right corner
8526     l      The center of the left edge
8527     c      In the center of the element
8528     r      The center of the right edge
8529     bl     The bottom left corner
8530     b      The center of the bottom edge
8531     br     The bottom right corner
8532     </pre>
8533     Example Usage:
8534     <pre><code>
8535     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8536     el.alignTo("other-el");
8537
8538     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8539     el.alignTo("other-el", "tr?");
8540
8541     // align the bottom right corner of el with the center left edge of other-el
8542     el.alignTo("other-el", "br-l?");
8543
8544     // align the center of el with the bottom left corner of other-el and
8545     // adjust the x position by -6 pixels (and the y position by 0)
8546     el.alignTo("other-el", "c-bl", [-6, 0]);
8547     </code></pre>
8548          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8549          * @param {String} position The position to align to.
8550          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8551          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8552          * @return {Roo.Element} this
8553          */
8554         alignTo : function(element, position, offsets, animate){
8555             var xy = this.getAlignToXY(element, position, offsets);
8556             this.setXY(xy, this.preanim(arguments, 3));
8557             return this;
8558         },
8559
8560         /**
8561          * Anchors an element to another element and realigns it when the window is resized.
8562          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8563          * @param {String} position The position to align to.
8564          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8565          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8566          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8567          * is a number, it is used as the buffer delay (defaults to 50ms).
8568          * @param {Function} callback The function to call after the animation finishes
8569          * @return {Roo.Element} this
8570          */
8571         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8572             var action = function(){
8573                 this.alignTo(el, alignment, offsets, animate);
8574                 Roo.callback(callback, this);
8575             };
8576             Roo.EventManager.onWindowResize(action, this);
8577             var tm = typeof monitorScroll;
8578             if(tm != 'undefined'){
8579                 Roo.EventManager.on(window, 'scroll', action, this,
8580                     {buffer: tm == 'number' ? monitorScroll : 50});
8581             }
8582             action.call(this); // align immediately
8583             return this;
8584         },
8585         /**
8586          * Clears any opacity settings from this element. Required in some cases for IE.
8587          * @return {Roo.Element} this
8588          */
8589         clearOpacity : function(){
8590             if (window.ActiveXObject) {
8591                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8592                     this.dom.style.filter = "";
8593                 }
8594             } else {
8595                 this.dom.style.opacity = "";
8596                 this.dom.style["-moz-opacity"] = "";
8597                 this.dom.style["-khtml-opacity"] = "";
8598             }
8599             return this;
8600         },
8601
8602         /**
8603          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8604          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8605          * @return {Roo.Element} this
8606          */
8607         hide : function(animate){
8608             this.setVisible(false, this.preanim(arguments, 0));
8609             return this;
8610         },
8611
8612         /**
8613         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8614         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8615          * @return {Roo.Element} this
8616          */
8617         show : function(animate){
8618             this.setVisible(true, this.preanim(arguments, 0));
8619             return this;
8620         },
8621
8622         /**
8623          * @private Test if size has a unit, otherwise appends the default
8624          */
8625         addUnits : function(size){
8626             return Roo.Element.addUnits(size, this.defaultUnit);
8627         },
8628
8629         /**
8630          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8631          * @return {Roo.Element} this
8632          */
8633         beginMeasure : function(){
8634             var el = this.dom;
8635             if(el.offsetWidth || el.offsetHeight){
8636                 return this; // offsets work already
8637             }
8638             var changed = [];
8639             var p = this.dom, b = document.body; // start with this element
8640             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8641                 var pe = Roo.get(p);
8642                 if(pe.getStyle('display') == 'none'){
8643                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8644                     p.style.visibility = "hidden";
8645                     p.style.display = "block";
8646                 }
8647                 p = p.parentNode;
8648             }
8649             this._measureChanged = changed;
8650             return this;
8651
8652         },
8653
8654         /**
8655          * Restores displays to before beginMeasure was called
8656          * @return {Roo.Element} this
8657          */
8658         endMeasure : function(){
8659             var changed = this._measureChanged;
8660             if(changed){
8661                 for(var i = 0, len = changed.length; i < len; i++) {
8662                     var r = changed[i];
8663                     r.el.style.visibility = r.visibility;
8664                     r.el.style.display = "none";
8665                 }
8666                 this._measureChanged = null;
8667             }
8668             return this;
8669         },
8670
8671         /**
8672         * Update the innerHTML of this element, optionally searching for and processing scripts
8673         * @param {String} html The new HTML
8674         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8675         * @param {Function} callback For async script loading you can be noticed when the update completes
8676         * @return {Roo.Element} this
8677          */
8678         update : function(html, loadScripts, callback){
8679             if(typeof html == "undefined"){
8680                 html = "";
8681             }
8682             if(loadScripts !== true){
8683                 this.dom.innerHTML = html;
8684                 if(typeof callback == "function"){
8685                     callback();
8686                 }
8687                 return this;
8688             }
8689             var id = Roo.id();
8690             var dom = this.dom;
8691
8692             html += '<span id="' + id + '"></span>';
8693
8694             E.onAvailable(id, function(){
8695                 var hd = document.getElementsByTagName("head")[0];
8696                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8697                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8698                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8699
8700                 var match;
8701                 while(match = re.exec(html)){
8702                     var attrs = match[1];
8703                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8704                     if(srcMatch && srcMatch[2]){
8705                        var s = document.createElement("script");
8706                        s.src = srcMatch[2];
8707                        var typeMatch = attrs.match(typeRe);
8708                        if(typeMatch && typeMatch[2]){
8709                            s.type = typeMatch[2];
8710                        }
8711                        hd.appendChild(s);
8712                     }else if(match[2] && match[2].length > 0){
8713                         if(window.execScript) {
8714                            window.execScript(match[2]);
8715                         } else {
8716                             /**
8717                              * eval:var:id
8718                              * eval:var:dom
8719                              * eval:var:html
8720                              * 
8721                              */
8722                            window.eval(match[2]);
8723                         }
8724                     }
8725                 }
8726                 var el = document.getElementById(id);
8727                 if(el){el.parentNode.removeChild(el);}
8728                 if(typeof callback == "function"){
8729                     callback();
8730                 }
8731             });
8732             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8733             return this;
8734         },
8735
8736         /**
8737          * Direct access to the UpdateManager update() method (takes the same parameters).
8738          * @param {String/Function} url The url for this request or a function to call to get the url
8739          * @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}
8740          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8741          * @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.
8742          * @return {Roo.Element} this
8743          */
8744         load : function(){
8745             var um = this.getUpdateManager();
8746             um.update.apply(um, arguments);
8747             return this;
8748         },
8749
8750         /**
8751         * Gets this element's UpdateManager
8752         * @return {Roo.UpdateManager} The UpdateManager
8753         */
8754         getUpdateManager : function(){
8755             if(!this.updateManager){
8756                 this.updateManager = new Roo.UpdateManager(this);
8757             }
8758             return this.updateManager;
8759         },
8760
8761         /**
8762          * Disables text selection for this element (normalized across browsers)
8763          * @return {Roo.Element} this
8764          */
8765         unselectable : function(){
8766             this.dom.unselectable = "on";
8767             this.swallowEvent("selectstart", true);
8768             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8769             this.addClass("x-unselectable");
8770             return this;
8771         },
8772
8773         /**
8774         * Calculates the x, y to center this element on the screen
8775         * @return {Array} The x, y values [x, y]
8776         */
8777         getCenterXY : function(){
8778             return this.getAlignToXY(document, 'c-c');
8779         },
8780
8781         /**
8782         * Centers the Element in either the viewport, or another Element.
8783         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8784         */
8785         center : function(centerIn){
8786             this.alignTo(centerIn || document, 'c-c');
8787             return this;
8788         },
8789
8790         /**
8791          * Tests various css rules/browsers to determine if this element uses a border box
8792          * @return {Boolean}
8793          */
8794         isBorderBox : function(){
8795             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8796         },
8797
8798         /**
8799          * Return a box {x, y, width, height} that can be used to set another elements
8800          * size/location to match this element.
8801          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8802          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8803          * @return {Object} box An object in the format {x, y, width, height}
8804          */
8805         getBox : function(contentBox, local){
8806             var xy;
8807             if(!local){
8808                 xy = this.getXY();
8809             }else{
8810                 var left = parseInt(this.getStyle("left"), 10) || 0;
8811                 var top = parseInt(this.getStyle("top"), 10) || 0;
8812                 xy = [left, top];
8813             }
8814             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8815             if(!contentBox){
8816                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8817             }else{
8818                 var l = this.getBorderWidth("l")+this.getPadding("l");
8819                 var r = this.getBorderWidth("r")+this.getPadding("r");
8820                 var t = this.getBorderWidth("t")+this.getPadding("t");
8821                 var b = this.getBorderWidth("b")+this.getPadding("b");
8822                 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)};
8823             }
8824             bx.right = bx.x + bx.width;
8825             bx.bottom = bx.y + bx.height;
8826             return bx;
8827         },
8828
8829         /**
8830          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8831          for more information about the sides.
8832          * @param {String} sides
8833          * @return {Number}
8834          */
8835         getFrameWidth : function(sides, onlyContentBox){
8836             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8837         },
8838
8839         /**
8840          * 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.
8841          * @param {Object} box The box to fill {x, y, width, height}
8842          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8843          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8844          * @return {Roo.Element} this
8845          */
8846         setBox : function(box, adjust, animate){
8847             var w = box.width, h = box.height;
8848             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8849                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8850                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8851             }
8852             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8853             return this;
8854         },
8855
8856         /**
8857          * Forces the browser to repaint this element
8858          * @return {Roo.Element} this
8859          */
8860          repaint : function(){
8861             var dom = this.dom;
8862             this.addClass("x-repaint");
8863             setTimeout(function(){
8864                 Roo.get(dom).removeClass("x-repaint");
8865             }, 1);
8866             return this;
8867         },
8868
8869         /**
8870          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8871          * then it returns the calculated width of the sides (see getPadding)
8872          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8873          * @return {Object/Number}
8874          */
8875         getMargins : function(side){
8876             if(!side){
8877                 return {
8878                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8879                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8880                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8881                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8882                 };
8883             }else{
8884                 return this.addStyles(side, El.margins);
8885              }
8886         },
8887
8888         // private
8889         addStyles : function(sides, styles){
8890             var val = 0, v, w;
8891             for(var i = 0, len = sides.length; i < len; i++){
8892                 v = this.getStyle(styles[sides.charAt(i)]);
8893                 if(v){
8894                      w = parseInt(v, 10);
8895                      if(w){ val += w; }
8896                 }
8897             }
8898             return val;
8899         },
8900
8901         /**
8902          * Creates a proxy element of this element
8903          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8904          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8905          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8906          * @return {Roo.Element} The new proxy element
8907          */
8908         createProxy : function(config, renderTo, matchBox){
8909             if(renderTo){
8910                 renderTo = Roo.getDom(renderTo);
8911             }else{
8912                 renderTo = document.body;
8913             }
8914             config = typeof config == "object" ?
8915                 config : {tag : "div", cls: config};
8916             var proxy = Roo.DomHelper.append(renderTo, config, true);
8917             if(matchBox){
8918                proxy.setBox(this.getBox());
8919             }
8920             return proxy;
8921         },
8922
8923         /**
8924          * Puts a mask over this element to disable user interaction. Requires core.css.
8925          * This method can only be applied to elements which accept child nodes.
8926          * @param {String} msg (optional) A message to display in the mask
8927          * @param {String} msgCls (optional) A css class to apply to the msg element
8928          * @return {Element} The mask  element
8929          */
8930         mask : function(msg, msgCls)
8931         {
8932             if(this.getStyle("position") == "static"){
8933                 this.setStyle("position", "relative");
8934             }
8935             if(!this._mask){
8936                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8937             }
8938             this.addClass("x-masked");
8939             this._mask.setDisplayed(true);
8940             
8941             // we wander
8942             var z = 0;
8943             var dom = this.dom
8944             while (dom && dom.style) {
8945                 if (!isNaN(parseInt(dom.style.zIndex))) {
8946                     z = Math.max(z, parseInt(dom.style.zIndex));
8947                 }
8948                 dom = dom.parentNode;
8949             }
8950             // if we are masking the body - then it hides everything..
8951             if (this.dom == document.body) {
8952                 z = 1000000;
8953                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8954                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8955             }
8956            
8957             if(typeof msg == 'string'){
8958                 if(!this._maskMsg){
8959                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8960                 }
8961                 var mm = this._maskMsg;
8962                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8963                 mm.dom.firstChild.innerHTML = msg;
8964                 mm.setDisplayed(true);
8965                 mm.center(this);
8966                 mm.setStyle('z-index', z + 102);
8967             }
8968             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8969                 this._mask.setHeight(this.getHeight());
8970             }
8971             this._mask.setStyle('z-index', z + 100);
8972             
8973             return this._mask;
8974         },
8975
8976         /**
8977          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8978          * it is cached for reuse.
8979          */
8980         unmask : function(removeEl){
8981             if(this._mask){
8982                 if(removeEl === true){
8983                     this._mask.remove();
8984                     delete this._mask;
8985                     if(this._maskMsg){
8986                         this._maskMsg.remove();
8987                         delete this._maskMsg;
8988                     }
8989                 }else{
8990                     this._mask.setDisplayed(false);
8991                     if(this._maskMsg){
8992                         this._maskMsg.setDisplayed(false);
8993                     }
8994                 }
8995             }
8996             this.removeClass("x-masked");
8997         },
8998
8999         /**
9000          * Returns true if this element is masked
9001          * @return {Boolean}
9002          */
9003         isMasked : function(){
9004             return this._mask && this._mask.isVisible();
9005         },
9006
9007         /**
9008          * Creates an iframe shim for this element to keep selects and other windowed objects from
9009          * showing through.
9010          * @return {Roo.Element} The new shim element
9011          */
9012         createShim : function(){
9013             var el = document.createElement('iframe');
9014             el.frameBorder = 'no';
9015             el.className = 'roo-shim';
9016             if(Roo.isIE && Roo.isSecure){
9017                 el.src = Roo.SSL_SECURE_URL;
9018             }
9019             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9020             shim.autoBoxAdjust = false;
9021             return shim;
9022         },
9023
9024         /**
9025          * Removes this element from the DOM and deletes it from the cache
9026          */
9027         remove : function(){
9028             if(this.dom.parentNode){
9029                 this.dom.parentNode.removeChild(this.dom);
9030             }
9031             delete El.cache[this.dom.id];
9032         },
9033
9034         /**
9035          * Sets up event handlers to add and remove a css class when the mouse is over this element
9036          * @param {String} className
9037          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9038          * mouseout events for children elements
9039          * @return {Roo.Element} this
9040          */
9041         addClassOnOver : function(className, preventFlicker){
9042             this.on("mouseover", function(){
9043                 Roo.fly(this, '_internal').addClass(className);
9044             }, this.dom);
9045             var removeFn = function(e){
9046                 if(preventFlicker !== true || !e.within(this, true)){
9047                     Roo.fly(this, '_internal').removeClass(className);
9048                 }
9049             };
9050             this.on("mouseout", removeFn, this.dom);
9051             return this;
9052         },
9053
9054         /**
9055          * Sets up event handlers to add and remove a css class when this element has the focus
9056          * @param {String} className
9057          * @return {Roo.Element} this
9058          */
9059         addClassOnFocus : function(className){
9060             this.on("focus", function(){
9061                 Roo.fly(this, '_internal').addClass(className);
9062             }, this.dom);
9063             this.on("blur", function(){
9064                 Roo.fly(this, '_internal').removeClass(className);
9065             }, this.dom);
9066             return this;
9067         },
9068         /**
9069          * 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)
9070          * @param {String} className
9071          * @return {Roo.Element} this
9072          */
9073         addClassOnClick : function(className){
9074             var dom = this.dom;
9075             this.on("mousedown", function(){
9076                 Roo.fly(dom, '_internal').addClass(className);
9077                 var d = Roo.get(document);
9078                 var fn = function(){
9079                     Roo.fly(dom, '_internal').removeClass(className);
9080                     d.removeListener("mouseup", fn);
9081                 };
9082                 d.on("mouseup", fn);
9083             });
9084             return this;
9085         },
9086
9087         /**
9088          * Stops the specified event from bubbling and optionally prevents the default action
9089          * @param {String} eventName
9090          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9091          * @return {Roo.Element} this
9092          */
9093         swallowEvent : function(eventName, preventDefault){
9094             var fn = function(e){
9095                 e.stopPropagation();
9096                 if(preventDefault){
9097                     e.preventDefault();
9098                 }
9099             };
9100             if(eventName instanceof Array){
9101                 for(var i = 0, len = eventName.length; i < len; i++){
9102                      this.on(eventName[i], fn);
9103                 }
9104                 return this;
9105             }
9106             this.on(eventName, fn);
9107             return this;
9108         },
9109
9110         /**
9111          * @private
9112          */
9113       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9114
9115         /**
9116          * Sizes this element to its parent element's dimensions performing
9117          * neccessary box adjustments.
9118          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9119          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9120          * @return {Roo.Element} this
9121          */
9122         fitToParent : function(monitorResize, targetParent) {
9123           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9124           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9125           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9126             return;
9127           }
9128           var p = Roo.get(targetParent || this.dom.parentNode);
9129           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9130           if (monitorResize === true) {
9131             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9132             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9133           }
9134           return this;
9135         },
9136
9137         /**
9138          * Gets the next sibling, skipping text nodes
9139          * @return {HTMLElement} The next sibling or null
9140          */
9141         getNextSibling : function(){
9142             var n = this.dom.nextSibling;
9143             while(n && n.nodeType != 1){
9144                 n = n.nextSibling;
9145             }
9146             return n;
9147         },
9148
9149         /**
9150          * Gets the previous sibling, skipping text nodes
9151          * @return {HTMLElement} The previous sibling or null
9152          */
9153         getPrevSibling : function(){
9154             var n = this.dom.previousSibling;
9155             while(n && n.nodeType != 1){
9156                 n = n.previousSibling;
9157             }
9158             return n;
9159         },
9160
9161
9162         /**
9163          * Appends the passed element(s) to this element
9164          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9165          * @return {Roo.Element} this
9166          */
9167         appendChild: function(el){
9168             el = Roo.get(el);
9169             el.appendTo(this);
9170             return this;
9171         },
9172
9173         /**
9174          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9175          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9176          * automatically generated with the specified attributes.
9177          * @param {HTMLElement} insertBefore (optional) a child element of this element
9178          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9179          * @return {Roo.Element} The new child element
9180          */
9181         createChild: function(config, insertBefore, returnDom){
9182             config = config || {tag:'div'};
9183             if(insertBefore){
9184                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9185             }
9186             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9187         },
9188
9189         /**
9190          * Appends this element to the passed element
9191          * @param {String/HTMLElement/Element} el The new parent element
9192          * @return {Roo.Element} this
9193          */
9194         appendTo: function(el){
9195             el = Roo.getDom(el);
9196             el.appendChild(this.dom);
9197             return this;
9198         },
9199
9200         /**
9201          * Inserts this element before the passed element in the DOM
9202          * @param {String/HTMLElement/Element} el The element to insert before
9203          * @return {Roo.Element} this
9204          */
9205         insertBefore: function(el){
9206             el = Roo.getDom(el);
9207             el.parentNode.insertBefore(this.dom, el);
9208             return this;
9209         },
9210
9211         /**
9212          * Inserts this element after the passed element in the DOM
9213          * @param {String/HTMLElement/Element} el The element to insert after
9214          * @return {Roo.Element} this
9215          */
9216         insertAfter: function(el){
9217             el = Roo.getDom(el);
9218             el.parentNode.insertBefore(this.dom, el.nextSibling);
9219             return this;
9220         },
9221
9222         /**
9223          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9224          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9225          * @return {Roo.Element} The new child
9226          */
9227         insertFirst: function(el, returnDom){
9228             el = el || {};
9229             if(typeof el == 'object' && !el.nodeType){ // dh config
9230                 return this.createChild(el, this.dom.firstChild, returnDom);
9231             }else{
9232                 el = Roo.getDom(el);
9233                 this.dom.insertBefore(el, this.dom.firstChild);
9234                 return !returnDom ? Roo.get(el) : el;
9235             }
9236         },
9237
9238         /**
9239          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9240          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9241          * @param {String} where (optional) 'before' or 'after' defaults to before
9242          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9243          * @return {Roo.Element} the inserted Element
9244          */
9245         insertSibling: function(el, where, returnDom){
9246             where = where ? where.toLowerCase() : 'before';
9247             el = el || {};
9248             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9249
9250             if(typeof el == 'object' && !el.nodeType){ // dh config
9251                 if(where == 'after' && !this.dom.nextSibling){
9252                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9253                 }else{
9254                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9255                 }
9256
9257             }else{
9258                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9259                             where == 'before' ? this.dom : this.dom.nextSibling);
9260                 if(!returnDom){
9261                     rt = Roo.get(rt);
9262                 }
9263             }
9264             return rt;
9265         },
9266
9267         /**
9268          * Creates and wraps this element with another element
9269          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9270          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9271          * @return {HTMLElement/Element} The newly created wrapper element
9272          */
9273         wrap: function(config, returnDom){
9274             if(!config){
9275                 config = {tag: "div"};
9276             }
9277             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9278             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9279             return newEl;
9280         },
9281
9282         /**
9283          * Replaces the passed element with this element
9284          * @param {String/HTMLElement/Element} el The element to replace
9285          * @return {Roo.Element} this
9286          */
9287         replace: function(el){
9288             el = Roo.get(el);
9289             this.insertBefore(el);
9290             el.remove();
9291             return this;
9292         },
9293
9294         /**
9295          * Inserts an html fragment into this element
9296          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9297          * @param {String} html The HTML fragment
9298          * @param {Boolean} returnEl True to return an Roo.Element
9299          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9300          */
9301         insertHtml : function(where, html, returnEl){
9302             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9303             return returnEl ? Roo.get(el) : el;
9304         },
9305
9306         /**
9307          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9308          * @param {Object} o The object with the attributes
9309          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9310          * @return {Roo.Element} this
9311          */
9312         set : function(o, useSet){
9313             var el = this.dom;
9314             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9315             for(var attr in o){
9316                 if(attr == "style" || typeof o[attr] == "function") continue;
9317                 if(attr=="cls"){
9318                     el.className = o["cls"];
9319                 }else{
9320                     if(useSet) el.setAttribute(attr, o[attr]);
9321                     else el[attr] = o[attr];
9322                 }
9323             }
9324             if(o.style){
9325                 Roo.DomHelper.applyStyles(el, o.style);
9326             }
9327             return this;
9328         },
9329
9330         /**
9331          * Convenience method for constructing a KeyMap
9332          * @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:
9333          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9334          * @param {Function} fn The function to call
9335          * @param {Object} scope (optional) The scope of the function
9336          * @return {Roo.KeyMap} The KeyMap created
9337          */
9338         addKeyListener : function(key, fn, scope){
9339             var config;
9340             if(typeof key != "object" || key instanceof Array){
9341                 config = {
9342                     key: key,
9343                     fn: fn,
9344                     scope: scope
9345                 };
9346             }else{
9347                 config = {
9348                     key : key.key,
9349                     shift : key.shift,
9350                     ctrl : key.ctrl,
9351                     alt : key.alt,
9352                     fn: fn,
9353                     scope: scope
9354                 };
9355             }
9356             return new Roo.KeyMap(this, config);
9357         },
9358
9359         /**
9360          * Creates a KeyMap for this element
9361          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9362          * @return {Roo.KeyMap} The KeyMap created
9363          */
9364         addKeyMap : function(config){
9365             return new Roo.KeyMap(this, config);
9366         },
9367
9368         /**
9369          * Returns true if this element is scrollable.
9370          * @return {Boolean}
9371          */
9372          isScrollable : function(){
9373             var dom = this.dom;
9374             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9375         },
9376
9377         /**
9378          * 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().
9379          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9380          * @param {Number} value The new scroll value
9381          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9382          * @return {Element} this
9383          */
9384
9385         scrollTo : function(side, value, animate){
9386             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9387             if(!animate || !A){
9388                 this.dom[prop] = value;
9389             }else{
9390                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9391                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9392             }
9393             return this;
9394         },
9395
9396         /**
9397          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9398          * within this element's scrollable range.
9399          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9400          * @param {Number} distance How far to scroll the element in pixels
9401          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9402          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9403          * was scrolled as far as it could go.
9404          */
9405          scroll : function(direction, distance, animate){
9406              if(!this.isScrollable()){
9407                  return;
9408              }
9409              var el = this.dom;
9410              var l = el.scrollLeft, t = el.scrollTop;
9411              var w = el.scrollWidth, h = el.scrollHeight;
9412              var cw = el.clientWidth, ch = el.clientHeight;
9413              direction = direction.toLowerCase();
9414              var scrolled = false;
9415              var a = this.preanim(arguments, 2);
9416              switch(direction){
9417                  case "l":
9418                  case "left":
9419                      if(w - l > cw){
9420                          var v = Math.min(l + distance, w-cw);
9421                          this.scrollTo("left", v, a);
9422                          scrolled = true;
9423                      }
9424                      break;
9425                 case "r":
9426                 case "right":
9427                      if(l > 0){
9428                          var v = Math.max(l - distance, 0);
9429                          this.scrollTo("left", v, a);
9430                          scrolled = true;
9431                      }
9432                      break;
9433                 case "t":
9434                 case "top":
9435                 case "up":
9436                      if(t > 0){
9437                          var v = Math.max(t - distance, 0);
9438                          this.scrollTo("top", v, a);
9439                          scrolled = true;
9440                      }
9441                      break;
9442                 case "b":
9443                 case "bottom":
9444                 case "down":
9445                      if(h - t > ch){
9446                          var v = Math.min(t + distance, h-ch);
9447                          this.scrollTo("top", v, a);
9448                          scrolled = true;
9449                      }
9450                      break;
9451              }
9452              return scrolled;
9453         },
9454
9455         /**
9456          * Translates the passed page coordinates into left/top css values for this element
9457          * @param {Number/Array} x The page x or an array containing [x, y]
9458          * @param {Number} y The page y
9459          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9460          */
9461         translatePoints : function(x, y){
9462             if(typeof x == 'object' || x instanceof Array){
9463                 y = x[1]; x = x[0];
9464             }
9465             var p = this.getStyle('position');
9466             var o = this.getXY();
9467
9468             var l = parseInt(this.getStyle('left'), 10);
9469             var t = parseInt(this.getStyle('top'), 10);
9470
9471             if(isNaN(l)){
9472                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9473             }
9474             if(isNaN(t)){
9475                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9476             }
9477
9478             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9479         },
9480
9481         /**
9482          * Returns the current scroll position of the element.
9483          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9484          */
9485         getScroll : function(){
9486             var d = this.dom, doc = document;
9487             if(d == doc || d == doc.body){
9488                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9489                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9490                 return {left: l, top: t};
9491             }else{
9492                 return {left: d.scrollLeft, top: d.scrollTop};
9493             }
9494         },
9495
9496         /**
9497          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9498          * are convert to standard 6 digit hex color.
9499          * @param {String} attr The css attribute
9500          * @param {String} defaultValue The default value to use when a valid color isn't found
9501          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9502          * YUI color anims.
9503          */
9504         getColor : function(attr, defaultValue, prefix){
9505             var v = this.getStyle(attr);
9506             if(!v || v == "transparent" || v == "inherit") {
9507                 return defaultValue;
9508             }
9509             var color = typeof prefix == "undefined" ? "#" : prefix;
9510             if(v.substr(0, 4) == "rgb("){
9511                 var rvs = v.slice(4, v.length -1).split(",");
9512                 for(var i = 0; i < 3; i++){
9513                     var h = parseInt(rvs[i]).toString(16);
9514                     if(h < 16){
9515                         h = "0" + h;
9516                     }
9517                     color += h;
9518                 }
9519             } else {
9520                 if(v.substr(0, 1) == "#"){
9521                     if(v.length == 4) {
9522                         for(var i = 1; i < 4; i++){
9523                             var c = v.charAt(i);
9524                             color +=  c + c;
9525                         }
9526                     }else if(v.length == 7){
9527                         color += v.substr(1);
9528                     }
9529                 }
9530             }
9531             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9532         },
9533
9534         /**
9535          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9536          * gradient background, rounded corners and a 4-way shadow.
9537          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9538          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9539          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9540          * @return {Roo.Element} this
9541          */
9542         boxWrap : function(cls){
9543             cls = cls || 'x-box';
9544             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9545             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9546             return el;
9547         },
9548
9549         /**
9550          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9551          * @param {String} namespace The namespace in which to look for the attribute
9552          * @param {String} name The attribute name
9553          * @return {String} The attribute value
9554          */
9555         getAttributeNS : Roo.isIE ? function(ns, name){
9556             var d = this.dom;
9557             var type = typeof d[ns+":"+name];
9558             if(type != 'undefined' && type != 'unknown'){
9559                 return d[ns+":"+name];
9560             }
9561             return d[name];
9562         } : function(ns, name){
9563             var d = this.dom;
9564             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9565         },
9566         
9567         
9568         /**
9569          * Sets or Returns the value the dom attribute value
9570          * @param {String} name The attribute name
9571          * @param {String} value (optional) The value to set the attribute to
9572          * @return {String} The attribute value
9573          */
9574         attr : function(name){
9575             if (arguments.length > 1) {
9576                 this.dom.setAttribute(name, arguments[1]);
9577                 return arguments[1];
9578             }
9579             if (!this.dom.hasAttribute(name)) {
9580                 return undefined;
9581             }
9582             return this.dom.getAttribute(name);
9583         }
9584         
9585         
9586         
9587     };
9588
9589     var ep = El.prototype;
9590
9591     /**
9592      * Appends an event handler (Shorthand for addListener)
9593      * @param {String}   eventName     The type of event to append
9594      * @param {Function} fn        The method the event invokes
9595      * @param {Object} scope       (optional) The scope (this object) of the fn
9596      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9597      * @method
9598      */
9599     ep.on = ep.addListener;
9600         // backwards compat
9601     ep.mon = ep.addListener;
9602
9603     /**
9604      * Removes an event handler from this element (shorthand for removeListener)
9605      * @param {String} eventName the type of event to remove
9606      * @param {Function} fn the method the event invokes
9607      * @return {Roo.Element} this
9608      * @method
9609      */
9610     ep.un = ep.removeListener;
9611
9612     /**
9613      * true to automatically adjust width and height settings for box-model issues (default to true)
9614      */
9615     ep.autoBoxAdjust = true;
9616
9617     // private
9618     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9619
9620     // private
9621     El.addUnits = function(v, defaultUnit){
9622         if(v === "" || v == "auto"){
9623             return v;
9624         }
9625         if(v === undefined){
9626             return '';
9627         }
9628         if(typeof v == "number" || !El.unitPattern.test(v)){
9629             return v + (defaultUnit || 'px');
9630         }
9631         return v;
9632     };
9633
9634     // special markup used throughout Roo when box wrapping elements
9635     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>';
9636     /**
9637      * Visibility mode constant - Use visibility to hide element
9638      * @static
9639      * @type Number
9640      */
9641     El.VISIBILITY = 1;
9642     /**
9643      * Visibility mode constant - Use display to hide element
9644      * @static
9645      * @type Number
9646      */
9647     El.DISPLAY = 2;
9648
9649     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9650     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9651     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9652
9653
9654
9655     /**
9656      * @private
9657      */
9658     El.cache = {};
9659
9660     var docEl;
9661
9662     /**
9663      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9664      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9665      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9666      * @return {Element} The Element object
9667      * @static
9668      */
9669     El.get = function(el){
9670         var ex, elm, id;
9671         if(!el){ return null; }
9672         if(typeof el == "string"){ // element id
9673             if(!(elm = document.getElementById(el))){
9674                 return null;
9675             }
9676             if(ex = El.cache[el]){
9677                 ex.dom = elm;
9678             }else{
9679                 ex = El.cache[el] = new El(elm);
9680             }
9681             return ex;
9682         }else if(el.tagName){ // dom element
9683             if(!(id = el.id)){
9684                 id = Roo.id(el);
9685             }
9686             if(ex = El.cache[id]){
9687                 ex.dom = el;
9688             }else{
9689                 ex = El.cache[id] = new El(el);
9690             }
9691             return ex;
9692         }else if(el instanceof El){
9693             if(el != docEl){
9694                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9695                                                               // catch case where it hasn't been appended
9696                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9697             }
9698             return el;
9699         }else if(el.isComposite){
9700             return el;
9701         }else if(el instanceof Array){
9702             return El.select(el);
9703         }else if(el == document){
9704             // create a bogus element object representing the document object
9705             if(!docEl){
9706                 var f = function(){};
9707                 f.prototype = El.prototype;
9708                 docEl = new f();
9709                 docEl.dom = document;
9710             }
9711             return docEl;
9712         }
9713         return null;
9714     };
9715
9716     // private
9717     El.uncache = function(el){
9718         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9719             if(a[i]){
9720                 delete El.cache[a[i].id || a[i]];
9721             }
9722         }
9723     };
9724
9725     // private
9726     // Garbage collection - uncache elements/purge listeners on orphaned elements
9727     // so we don't hold a reference and cause the browser to retain them
9728     El.garbageCollect = function(){
9729         if(!Roo.enableGarbageCollector){
9730             clearInterval(El.collectorThread);
9731             return;
9732         }
9733         for(var eid in El.cache){
9734             var el = El.cache[eid], d = el.dom;
9735             // -------------------------------------------------------
9736             // Determining what is garbage:
9737             // -------------------------------------------------------
9738             // !d
9739             // dom node is null, definitely garbage
9740             // -------------------------------------------------------
9741             // !d.parentNode
9742             // no parentNode == direct orphan, definitely garbage
9743             // -------------------------------------------------------
9744             // !d.offsetParent && !document.getElementById(eid)
9745             // display none elements have no offsetParent so we will
9746             // also try to look it up by it's id. However, check
9747             // offsetParent first so we don't do unneeded lookups.
9748             // This enables collection of elements that are not orphans
9749             // directly, but somewhere up the line they have an orphan
9750             // parent.
9751             // -------------------------------------------------------
9752             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9753                 delete El.cache[eid];
9754                 if(d && Roo.enableListenerCollection){
9755                     E.purgeElement(d);
9756                 }
9757             }
9758         }
9759     }
9760     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9761
9762
9763     // dom is optional
9764     El.Flyweight = function(dom){
9765         this.dom = dom;
9766     };
9767     El.Flyweight.prototype = El.prototype;
9768
9769     El._flyweights = {};
9770     /**
9771      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9772      * the dom node can be overwritten by other code.
9773      * @param {String/HTMLElement} el The dom node or id
9774      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9775      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9776      * @static
9777      * @return {Element} The shared Element object
9778      */
9779     El.fly = function(el, named){
9780         named = named || '_global';
9781         el = Roo.getDom(el);
9782         if(!el){
9783             return null;
9784         }
9785         if(!El._flyweights[named]){
9786             El._flyweights[named] = new El.Flyweight();
9787         }
9788         El._flyweights[named].dom = el;
9789         return El._flyweights[named];
9790     };
9791
9792     /**
9793      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9794      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9795      * Shorthand of {@link Roo.Element#get}
9796      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9797      * @return {Element} The Element object
9798      * @member Roo
9799      * @method get
9800      */
9801     Roo.get = El.get;
9802     /**
9803      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9804      * the dom node can be overwritten by other code.
9805      * Shorthand of {@link Roo.Element#fly}
9806      * @param {String/HTMLElement} el The dom node or id
9807      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9808      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9809      * @static
9810      * @return {Element} The shared Element object
9811      * @member Roo
9812      * @method fly
9813      */
9814     Roo.fly = El.fly;
9815
9816     // speedy lookup for elements never to box adjust
9817     var noBoxAdjust = Roo.isStrict ? {
9818         select:1
9819     } : {
9820         input:1, select:1, textarea:1
9821     };
9822     if(Roo.isIE || Roo.isGecko){
9823         noBoxAdjust['button'] = 1;
9824     }
9825
9826
9827     Roo.EventManager.on(window, 'unload', function(){
9828         delete El.cache;
9829         delete El._flyweights;
9830     });
9831 })();
9832
9833
9834
9835
9836 if(Roo.DomQuery){
9837     Roo.Element.selectorFunction = Roo.DomQuery.select;
9838 }
9839
9840 Roo.Element.select = function(selector, unique, root){
9841     var els;
9842     if(typeof selector == "string"){
9843         els = Roo.Element.selectorFunction(selector, root);
9844     }else if(selector.length !== undefined){
9845         els = selector;
9846     }else{
9847         throw "Invalid selector";
9848     }
9849     if(unique === true){
9850         return new Roo.CompositeElement(els);
9851     }else{
9852         return new Roo.CompositeElementLite(els);
9853     }
9854 };
9855 /**
9856  * Selects elements based on the passed CSS selector to enable working on them as 1.
9857  * @param {String/Array} selector The CSS selector or an array of elements
9858  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9859  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9860  * @return {CompositeElementLite/CompositeElement}
9861  * @member Roo
9862  * @method select
9863  */
9864 Roo.select = Roo.Element.select;
9865
9866
9867
9868
9869
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879 /*
9880  * Based on:
9881  * Ext JS Library 1.1.1
9882  * Copyright(c) 2006-2007, Ext JS, LLC.
9883  *
9884  * Originally Released Under LGPL - original licence link has changed is not relivant.
9885  *
9886  * Fork - LGPL
9887  * <script type="text/javascript">
9888  */
9889
9890
9891
9892 //Notifies Element that fx methods are available
9893 Roo.enableFx = true;
9894
9895 /**
9896  * @class Roo.Fx
9897  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9898  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9899  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9900  * Element effects to work.</p><br/>
9901  *
9902  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9903  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9904  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9905  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9906  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9907  * expected results and should be done with care.</p><br/>
9908  *
9909  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9910  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9911 <pre>
9912 Value  Description
9913 -----  -----------------------------
9914 tl     The top left corner
9915 t      The center of the top edge
9916 tr     The top right corner
9917 l      The center of the left edge
9918 r      The center of the right edge
9919 bl     The bottom left corner
9920 b      The center of the bottom edge
9921 br     The bottom right corner
9922 </pre>
9923  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9924  * below are common options that can be passed to any Fx method.</b>
9925  * @cfg {Function} callback A function called when the effect is finished
9926  * @cfg {Object} scope The scope of the effect function
9927  * @cfg {String} easing A valid Easing value for the effect
9928  * @cfg {String} afterCls A css class to apply after the effect
9929  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9930  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9931  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9932  * effects that end with the element being visually hidden, ignored otherwise)
9933  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9934  * a function which returns such a specification that will be applied to the Element after the effect finishes
9935  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9936  * @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
9937  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9938  */
9939 Roo.Fx = {
9940         /**
9941          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9942          * origin for the slide effect.  This function automatically handles wrapping the element with
9943          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9944          * Usage:
9945          *<pre><code>
9946 // default: slide the element in from the top
9947 el.slideIn();
9948
9949 // custom: slide the element in from the right with a 2-second duration
9950 el.slideIn('r', { duration: 2 });
9951
9952 // common config options shown with default values
9953 el.slideIn('t', {
9954     easing: 'easeOut',
9955     duration: .5
9956 });
9957 </code></pre>
9958          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9959          * @param {Object} options (optional) Object literal with any of the Fx config options
9960          * @return {Roo.Element} The Element
9961          */
9962     slideIn : function(anchor, o){
9963         var el = this.getFxEl();
9964         o = o || {};
9965
9966         el.queueFx(o, function(){
9967
9968             anchor = anchor || "t";
9969
9970             // fix display to visibility
9971             this.fixDisplay();
9972
9973             // restore values after effect
9974             var r = this.getFxRestore();
9975             var b = this.getBox();
9976             // fixed size for slide
9977             this.setSize(b);
9978
9979             // wrap if needed
9980             var wrap = this.fxWrap(r.pos, o, "hidden");
9981
9982             var st = this.dom.style;
9983             st.visibility = "visible";
9984             st.position = "absolute";
9985
9986             // clear out temp styles after slide and unwrap
9987             var after = function(){
9988                 el.fxUnwrap(wrap, r.pos, o);
9989                 st.width = r.width;
9990                 st.height = r.height;
9991                 el.afterFx(o);
9992             };
9993             // time to calc the positions
9994             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9995
9996             switch(anchor.toLowerCase()){
9997                 case "t":
9998                     wrap.setSize(b.width, 0);
9999                     st.left = st.bottom = "0";
10000                     a = {height: bh};
10001                 break;
10002                 case "l":
10003                     wrap.setSize(0, b.height);
10004                     st.right = st.top = "0";
10005                     a = {width: bw};
10006                 break;
10007                 case "r":
10008                     wrap.setSize(0, b.height);
10009                     wrap.setX(b.right);
10010                     st.left = st.top = "0";
10011                     a = {width: bw, points: pt};
10012                 break;
10013                 case "b":
10014                     wrap.setSize(b.width, 0);
10015                     wrap.setY(b.bottom);
10016                     st.left = st.top = "0";
10017                     a = {height: bh, points: pt};
10018                 break;
10019                 case "tl":
10020                     wrap.setSize(0, 0);
10021                     st.right = st.bottom = "0";
10022                     a = {width: bw, height: bh};
10023                 break;
10024                 case "bl":
10025                     wrap.setSize(0, 0);
10026                     wrap.setY(b.y+b.height);
10027                     st.right = st.top = "0";
10028                     a = {width: bw, height: bh, points: pt};
10029                 break;
10030                 case "br":
10031                     wrap.setSize(0, 0);
10032                     wrap.setXY([b.right, b.bottom]);
10033                     st.left = st.top = "0";
10034                     a = {width: bw, height: bh, points: pt};
10035                 break;
10036                 case "tr":
10037                     wrap.setSize(0, 0);
10038                     wrap.setX(b.x+b.width);
10039                     st.left = st.bottom = "0";
10040                     a = {width: bw, height: bh, points: pt};
10041                 break;
10042             }
10043             this.dom.style.visibility = "visible";
10044             wrap.show();
10045
10046             arguments.callee.anim = wrap.fxanim(a,
10047                 o,
10048                 'motion',
10049                 .5,
10050                 'easeOut', after);
10051         });
10052         return this;
10053     },
10054     
10055         /**
10056          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10057          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10058          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10059          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10060          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10061          * Usage:
10062          *<pre><code>
10063 // default: slide the element out to the top
10064 el.slideOut();
10065
10066 // custom: slide the element out to the right with a 2-second duration
10067 el.slideOut('r', { duration: 2 });
10068
10069 // common config options shown with default values
10070 el.slideOut('t', {
10071     easing: 'easeOut',
10072     duration: .5,
10073     remove: false,
10074     useDisplay: false
10075 });
10076 </code></pre>
10077          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10078          * @param {Object} options (optional) Object literal with any of the Fx config options
10079          * @return {Roo.Element} The Element
10080          */
10081     slideOut : function(anchor, o){
10082         var el = this.getFxEl();
10083         o = o || {};
10084
10085         el.queueFx(o, function(){
10086
10087             anchor = anchor || "t";
10088
10089             // restore values after effect
10090             var r = this.getFxRestore();
10091             
10092             var b = this.getBox();
10093             // fixed size for slide
10094             this.setSize(b);
10095
10096             // wrap if needed
10097             var wrap = this.fxWrap(r.pos, o, "visible");
10098
10099             var st = this.dom.style;
10100             st.visibility = "visible";
10101             st.position = "absolute";
10102
10103             wrap.setSize(b);
10104
10105             var after = function(){
10106                 if(o.useDisplay){
10107                     el.setDisplayed(false);
10108                 }else{
10109                     el.hide();
10110                 }
10111
10112                 el.fxUnwrap(wrap, r.pos, o);
10113
10114                 st.width = r.width;
10115                 st.height = r.height;
10116
10117                 el.afterFx(o);
10118             };
10119
10120             var a, zero = {to: 0};
10121             switch(anchor.toLowerCase()){
10122                 case "t":
10123                     st.left = st.bottom = "0";
10124                     a = {height: zero};
10125                 break;
10126                 case "l":
10127                     st.right = st.top = "0";
10128                     a = {width: zero};
10129                 break;
10130                 case "r":
10131                     st.left = st.top = "0";
10132                     a = {width: zero, points: {to:[b.right, b.y]}};
10133                 break;
10134                 case "b":
10135                     st.left = st.top = "0";
10136                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10137                 break;
10138                 case "tl":
10139                     st.right = st.bottom = "0";
10140                     a = {width: zero, height: zero};
10141                 break;
10142                 case "bl":
10143                     st.right = st.top = "0";
10144                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10145                 break;
10146                 case "br":
10147                     st.left = st.top = "0";
10148                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10149                 break;
10150                 case "tr":
10151                     st.left = st.bottom = "0";
10152                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10153                 break;
10154             }
10155
10156             arguments.callee.anim = wrap.fxanim(a,
10157                 o,
10158                 'motion',
10159                 .5,
10160                 "easeOut", after);
10161         });
10162         return this;
10163     },
10164
10165         /**
10166          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10167          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10168          * The element must be removed from the DOM using the 'remove' config option if desired.
10169          * Usage:
10170          *<pre><code>
10171 // default
10172 el.puff();
10173
10174 // common config options shown with default values
10175 el.puff({
10176     easing: 'easeOut',
10177     duration: .5,
10178     remove: false,
10179     useDisplay: false
10180 });
10181 </code></pre>
10182          * @param {Object} options (optional) Object literal with any of the Fx config options
10183          * @return {Roo.Element} The Element
10184          */
10185     puff : function(o){
10186         var el = this.getFxEl();
10187         o = o || {};
10188
10189         el.queueFx(o, function(){
10190             this.clearOpacity();
10191             this.show();
10192
10193             // restore values after effect
10194             var r = this.getFxRestore();
10195             var st = this.dom.style;
10196
10197             var after = function(){
10198                 if(o.useDisplay){
10199                     el.setDisplayed(false);
10200                 }else{
10201                     el.hide();
10202                 }
10203
10204                 el.clearOpacity();
10205
10206                 el.setPositioning(r.pos);
10207                 st.width = r.width;
10208                 st.height = r.height;
10209                 st.fontSize = '';
10210                 el.afterFx(o);
10211             };
10212
10213             var width = this.getWidth();
10214             var height = this.getHeight();
10215
10216             arguments.callee.anim = this.fxanim({
10217                     width : {to: this.adjustWidth(width * 2)},
10218                     height : {to: this.adjustHeight(height * 2)},
10219                     points : {by: [-(width * .5), -(height * .5)]},
10220                     opacity : {to: 0},
10221                     fontSize: {to:200, unit: "%"}
10222                 },
10223                 o,
10224                 'motion',
10225                 .5,
10226                 "easeOut", after);
10227         });
10228         return this;
10229     },
10230
10231         /**
10232          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10233          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10234          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10235          * Usage:
10236          *<pre><code>
10237 // default
10238 el.switchOff();
10239
10240 // all config options shown with default values
10241 el.switchOff({
10242     easing: 'easeIn',
10243     duration: .3,
10244     remove: false,
10245     useDisplay: false
10246 });
10247 </code></pre>
10248          * @param {Object} options (optional) Object literal with any of the Fx config options
10249          * @return {Roo.Element} The Element
10250          */
10251     switchOff : function(o){
10252         var el = this.getFxEl();
10253         o = o || {};
10254
10255         el.queueFx(o, function(){
10256             this.clearOpacity();
10257             this.clip();
10258
10259             // restore values after effect
10260             var r = this.getFxRestore();
10261             var st = this.dom.style;
10262
10263             var after = function(){
10264                 if(o.useDisplay){
10265                     el.setDisplayed(false);
10266                 }else{
10267                     el.hide();
10268                 }
10269
10270                 el.clearOpacity();
10271                 el.setPositioning(r.pos);
10272                 st.width = r.width;
10273                 st.height = r.height;
10274
10275                 el.afterFx(o);
10276             };
10277
10278             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10279                 this.clearOpacity();
10280                 (function(){
10281                     this.fxanim({
10282                         height:{to:1},
10283                         points:{by:[0, this.getHeight() * .5]}
10284                     }, o, 'motion', 0.3, 'easeIn', after);
10285                 }).defer(100, this);
10286             });
10287         });
10288         return this;
10289     },
10290
10291     /**
10292      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10293      * changed using the "attr" config option) and then fading back to the original color. If no original
10294      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10295      * Usage:
10296 <pre><code>
10297 // default: highlight background to yellow
10298 el.highlight();
10299
10300 // custom: highlight foreground text to blue for 2 seconds
10301 el.highlight("0000ff", { attr: 'color', duration: 2 });
10302
10303 // common config options shown with default values
10304 el.highlight("ffff9c", {
10305     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10306     endColor: (current color) or "ffffff",
10307     easing: 'easeIn',
10308     duration: 1
10309 });
10310 </code></pre>
10311      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10312      * @param {Object} options (optional) Object literal with any of the Fx config options
10313      * @return {Roo.Element} The Element
10314      */ 
10315     highlight : function(color, o){
10316         var el = this.getFxEl();
10317         o = o || {};
10318
10319         el.queueFx(o, function(){
10320             color = color || "ffff9c";
10321             attr = o.attr || "backgroundColor";
10322
10323             this.clearOpacity();
10324             this.show();
10325
10326             var origColor = this.getColor(attr);
10327             var restoreColor = this.dom.style[attr];
10328             endColor = (o.endColor || origColor) || "ffffff";
10329
10330             var after = function(){
10331                 el.dom.style[attr] = restoreColor;
10332                 el.afterFx(o);
10333             };
10334
10335             var a = {};
10336             a[attr] = {from: color, to: endColor};
10337             arguments.callee.anim = this.fxanim(a,
10338                 o,
10339                 'color',
10340                 1,
10341                 'easeIn', after);
10342         });
10343         return this;
10344     },
10345
10346    /**
10347     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10348     * Usage:
10349 <pre><code>
10350 // default: a single light blue ripple
10351 el.frame();
10352
10353 // custom: 3 red ripples lasting 3 seconds total
10354 el.frame("ff0000", 3, { duration: 3 });
10355
10356 // common config options shown with default values
10357 el.frame("C3DAF9", 1, {
10358     duration: 1 //duration of entire animation (not each individual ripple)
10359     // Note: Easing is not configurable and will be ignored if included
10360 });
10361 </code></pre>
10362     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10363     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10364     * @param {Object} options (optional) Object literal with any of the Fx config options
10365     * @return {Roo.Element} The Element
10366     */
10367     frame : function(color, count, o){
10368         var el = this.getFxEl();
10369         o = o || {};
10370
10371         el.queueFx(o, function(){
10372             color = color || "#C3DAF9";
10373             if(color.length == 6){
10374                 color = "#" + color;
10375             }
10376             count = count || 1;
10377             duration = o.duration || 1;
10378             this.show();
10379
10380             var b = this.getBox();
10381             var animFn = function(){
10382                 var proxy = this.createProxy({
10383
10384                      style:{
10385                         visbility:"hidden",
10386                         position:"absolute",
10387                         "z-index":"35000", // yee haw
10388                         border:"0px solid " + color
10389                      }
10390                   });
10391                 var scale = Roo.isBorderBox ? 2 : 1;
10392                 proxy.animate({
10393                     top:{from:b.y, to:b.y - 20},
10394                     left:{from:b.x, to:b.x - 20},
10395                     borderWidth:{from:0, to:10},
10396                     opacity:{from:1, to:0},
10397                     height:{from:b.height, to:(b.height + (20*scale))},
10398                     width:{from:b.width, to:(b.width + (20*scale))}
10399                 }, duration, function(){
10400                     proxy.remove();
10401                 });
10402                 if(--count > 0){
10403                      animFn.defer((duration/2)*1000, this);
10404                 }else{
10405                     el.afterFx(o);
10406                 }
10407             };
10408             animFn.call(this);
10409         });
10410         return this;
10411     },
10412
10413    /**
10414     * Creates a pause before any subsequent queued effects begin.  If there are
10415     * no effects queued after the pause it will have no effect.
10416     * Usage:
10417 <pre><code>
10418 el.pause(1);
10419 </code></pre>
10420     * @param {Number} seconds The length of time to pause (in seconds)
10421     * @return {Roo.Element} The Element
10422     */
10423     pause : function(seconds){
10424         var el = this.getFxEl();
10425         var o = {};
10426
10427         el.queueFx(o, function(){
10428             setTimeout(function(){
10429                 el.afterFx(o);
10430             }, seconds * 1000);
10431         });
10432         return this;
10433     },
10434
10435    /**
10436     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10437     * using the "endOpacity" config option.
10438     * Usage:
10439 <pre><code>
10440 // default: fade in from opacity 0 to 100%
10441 el.fadeIn();
10442
10443 // custom: fade in from opacity 0 to 75% over 2 seconds
10444 el.fadeIn({ endOpacity: .75, duration: 2});
10445
10446 // common config options shown with default values
10447 el.fadeIn({
10448     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10449     easing: 'easeOut',
10450     duration: .5
10451 });
10452 </code></pre>
10453     * @param {Object} options (optional) Object literal with any of the Fx config options
10454     * @return {Roo.Element} The Element
10455     */
10456     fadeIn : function(o){
10457         var el = this.getFxEl();
10458         o = o || {};
10459         el.queueFx(o, function(){
10460             this.setOpacity(0);
10461             this.fixDisplay();
10462             this.dom.style.visibility = 'visible';
10463             var to = o.endOpacity || 1;
10464             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10465                 o, null, .5, "easeOut", function(){
10466                 if(to == 1){
10467                     this.clearOpacity();
10468                 }
10469                 el.afterFx(o);
10470             });
10471         });
10472         return this;
10473     },
10474
10475    /**
10476     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10477     * using the "endOpacity" config option.
10478     * Usage:
10479 <pre><code>
10480 // default: fade out from the element's current opacity to 0
10481 el.fadeOut();
10482
10483 // custom: fade out from the element's current opacity to 25% over 2 seconds
10484 el.fadeOut({ endOpacity: .25, duration: 2});
10485
10486 // common config options shown with default values
10487 el.fadeOut({
10488     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10489     easing: 'easeOut',
10490     duration: .5
10491     remove: false,
10492     useDisplay: false
10493 });
10494 </code></pre>
10495     * @param {Object} options (optional) Object literal with any of the Fx config options
10496     * @return {Roo.Element} The Element
10497     */
10498     fadeOut : function(o){
10499         var el = this.getFxEl();
10500         o = o || {};
10501         el.queueFx(o, function(){
10502             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10503                 o, null, .5, "easeOut", function(){
10504                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10505                      this.dom.style.display = "none";
10506                 }else{
10507                      this.dom.style.visibility = "hidden";
10508                 }
10509                 this.clearOpacity();
10510                 el.afterFx(o);
10511             });
10512         });
10513         return this;
10514     },
10515
10516    /**
10517     * Animates the transition of an element's dimensions from a starting height/width
10518     * to an ending height/width.
10519     * Usage:
10520 <pre><code>
10521 // change height and width to 100x100 pixels
10522 el.scale(100, 100);
10523
10524 // common config options shown with default values.  The height and width will default to
10525 // the element's existing values if passed as null.
10526 el.scale(
10527     [element's width],
10528     [element's height], {
10529     easing: 'easeOut',
10530     duration: .35
10531 });
10532 </code></pre>
10533     * @param {Number} width  The new width (pass undefined to keep the original width)
10534     * @param {Number} height  The new height (pass undefined to keep the original height)
10535     * @param {Object} options (optional) Object literal with any of the Fx config options
10536     * @return {Roo.Element} The Element
10537     */
10538     scale : function(w, h, o){
10539         this.shift(Roo.apply({}, o, {
10540             width: w,
10541             height: h
10542         }));
10543         return this;
10544     },
10545
10546    /**
10547     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10548     * Any of these properties not specified in the config object will not be changed.  This effect 
10549     * requires that at least one new dimension, position or opacity setting must be passed in on
10550     * the config object in order for the function to have any effect.
10551     * Usage:
10552 <pre><code>
10553 // slide the element horizontally to x position 200 while changing the height and opacity
10554 el.shift({ x: 200, height: 50, opacity: .8 });
10555
10556 // common config options shown with default values.
10557 el.shift({
10558     width: [element's width],
10559     height: [element's height],
10560     x: [element's x position],
10561     y: [element's y position],
10562     opacity: [element's opacity],
10563     easing: 'easeOut',
10564     duration: .35
10565 });
10566 </code></pre>
10567     * @param {Object} options  Object literal with any of the Fx config options
10568     * @return {Roo.Element} The Element
10569     */
10570     shift : function(o){
10571         var el = this.getFxEl();
10572         o = o || {};
10573         el.queueFx(o, function(){
10574             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10575             if(w !== undefined){
10576                 a.width = {to: this.adjustWidth(w)};
10577             }
10578             if(h !== undefined){
10579                 a.height = {to: this.adjustHeight(h)};
10580             }
10581             if(x !== undefined || y !== undefined){
10582                 a.points = {to: [
10583                     x !== undefined ? x : this.getX(),
10584                     y !== undefined ? y : this.getY()
10585                 ]};
10586             }
10587             if(op !== undefined){
10588                 a.opacity = {to: op};
10589             }
10590             if(o.xy !== undefined){
10591                 a.points = {to: o.xy};
10592             }
10593             arguments.callee.anim = this.fxanim(a,
10594                 o, 'motion', .35, "easeOut", function(){
10595                 el.afterFx(o);
10596             });
10597         });
10598         return this;
10599     },
10600
10601         /**
10602          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10603          * ending point of the effect.
10604          * Usage:
10605          *<pre><code>
10606 // default: slide the element downward while fading out
10607 el.ghost();
10608
10609 // custom: slide the element out to the right with a 2-second duration
10610 el.ghost('r', { duration: 2 });
10611
10612 // common config options shown with default values
10613 el.ghost('b', {
10614     easing: 'easeOut',
10615     duration: .5
10616     remove: false,
10617     useDisplay: false
10618 });
10619 </code></pre>
10620          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10621          * @param {Object} options (optional) Object literal with any of the Fx config options
10622          * @return {Roo.Element} The Element
10623          */
10624     ghost : function(anchor, o){
10625         var el = this.getFxEl();
10626         o = o || {};
10627
10628         el.queueFx(o, function(){
10629             anchor = anchor || "b";
10630
10631             // restore values after effect
10632             var r = this.getFxRestore();
10633             var w = this.getWidth(),
10634                 h = this.getHeight();
10635
10636             var st = this.dom.style;
10637
10638             var after = function(){
10639                 if(o.useDisplay){
10640                     el.setDisplayed(false);
10641                 }else{
10642                     el.hide();
10643                 }
10644
10645                 el.clearOpacity();
10646                 el.setPositioning(r.pos);
10647                 st.width = r.width;
10648                 st.height = r.height;
10649
10650                 el.afterFx(o);
10651             };
10652
10653             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10654             switch(anchor.toLowerCase()){
10655                 case "t":
10656                     pt.by = [0, -h];
10657                 break;
10658                 case "l":
10659                     pt.by = [-w, 0];
10660                 break;
10661                 case "r":
10662                     pt.by = [w, 0];
10663                 break;
10664                 case "b":
10665                     pt.by = [0, h];
10666                 break;
10667                 case "tl":
10668                     pt.by = [-w, -h];
10669                 break;
10670                 case "bl":
10671                     pt.by = [-w, h];
10672                 break;
10673                 case "br":
10674                     pt.by = [w, h];
10675                 break;
10676                 case "tr":
10677                     pt.by = [w, -h];
10678                 break;
10679             }
10680
10681             arguments.callee.anim = this.fxanim(a,
10682                 o,
10683                 'motion',
10684                 .5,
10685                 "easeOut", after);
10686         });
10687         return this;
10688     },
10689
10690         /**
10691          * Ensures that all effects queued after syncFx is called on the element are
10692          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10693          * @return {Roo.Element} The Element
10694          */
10695     syncFx : function(){
10696         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10697             block : false,
10698             concurrent : true,
10699             stopFx : false
10700         });
10701         return this;
10702     },
10703
10704         /**
10705          * Ensures that all effects queued after sequenceFx is called on the element are
10706          * run in sequence.  This is the opposite of {@link #syncFx}.
10707          * @return {Roo.Element} The Element
10708          */
10709     sequenceFx : function(){
10710         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10711             block : false,
10712             concurrent : false,
10713             stopFx : false
10714         });
10715         return this;
10716     },
10717
10718         /* @private */
10719     nextFx : function(){
10720         var ef = this.fxQueue[0];
10721         if(ef){
10722             ef.call(this);
10723         }
10724     },
10725
10726         /**
10727          * Returns true if the element has any effects actively running or queued, else returns false.
10728          * @return {Boolean} True if element has active effects, else false
10729          */
10730     hasActiveFx : function(){
10731         return this.fxQueue && this.fxQueue[0];
10732     },
10733
10734         /**
10735          * Stops any running effects and clears the element's internal effects queue if it contains
10736          * any additional effects that haven't started yet.
10737          * @return {Roo.Element} The Element
10738          */
10739     stopFx : function(){
10740         if(this.hasActiveFx()){
10741             var cur = this.fxQueue[0];
10742             if(cur && cur.anim && cur.anim.isAnimated()){
10743                 this.fxQueue = [cur]; // clear out others
10744                 cur.anim.stop(true);
10745             }
10746         }
10747         return this;
10748     },
10749
10750         /* @private */
10751     beforeFx : function(o){
10752         if(this.hasActiveFx() && !o.concurrent){
10753            if(o.stopFx){
10754                this.stopFx();
10755                return true;
10756            }
10757            return false;
10758         }
10759         return true;
10760     },
10761
10762         /**
10763          * Returns true if the element is currently blocking so that no other effect can be queued
10764          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10765          * used to ensure that an effect initiated by a user action runs to completion prior to the
10766          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10767          * @return {Boolean} True if blocking, else false
10768          */
10769     hasFxBlock : function(){
10770         var q = this.fxQueue;
10771         return q && q[0] && q[0].block;
10772     },
10773
10774         /* @private */
10775     queueFx : function(o, fn){
10776         if(!this.fxQueue){
10777             this.fxQueue = [];
10778         }
10779         if(!this.hasFxBlock()){
10780             Roo.applyIf(o, this.fxDefaults);
10781             if(!o.concurrent){
10782                 var run = this.beforeFx(o);
10783                 fn.block = o.block;
10784                 this.fxQueue.push(fn);
10785                 if(run){
10786                     this.nextFx();
10787                 }
10788             }else{
10789                 fn.call(this);
10790             }
10791         }
10792         return this;
10793     },
10794
10795         /* @private */
10796     fxWrap : function(pos, o, vis){
10797         var wrap;
10798         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10799             var wrapXY;
10800             if(o.fixPosition){
10801                 wrapXY = this.getXY();
10802             }
10803             var div = document.createElement("div");
10804             div.style.visibility = vis;
10805             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10806             wrap.setPositioning(pos);
10807             if(wrap.getStyle("position") == "static"){
10808                 wrap.position("relative");
10809             }
10810             this.clearPositioning('auto');
10811             wrap.clip();
10812             wrap.dom.appendChild(this.dom);
10813             if(wrapXY){
10814                 wrap.setXY(wrapXY);
10815             }
10816         }
10817         return wrap;
10818     },
10819
10820         /* @private */
10821     fxUnwrap : function(wrap, pos, o){
10822         this.clearPositioning();
10823         this.setPositioning(pos);
10824         if(!o.wrap){
10825             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10826             wrap.remove();
10827         }
10828     },
10829
10830         /* @private */
10831     getFxRestore : function(){
10832         var st = this.dom.style;
10833         return {pos: this.getPositioning(), width: st.width, height : st.height};
10834     },
10835
10836         /* @private */
10837     afterFx : function(o){
10838         if(o.afterStyle){
10839             this.applyStyles(o.afterStyle);
10840         }
10841         if(o.afterCls){
10842             this.addClass(o.afterCls);
10843         }
10844         if(o.remove === true){
10845             this.remove();
10846         }
10847         Roo.callback(o.callback, o.scope, [this]);
10848         if(!o.concurrent){
10849             this.fxQueue.shift();
10850             this.nextFx();
10851         }
10852     },
10853
10854         /* @private */
10855     getFxEl : function(){ // support for composite element fx
10856         return Roo.get(this.dom);
10857     },
10858
10859         /* @private */
10860     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10861         animType = animType || 'run';
10862         opt = opt || {};
10863         var anim = Roo.lib.Anim[animType](
10864             this.dom, args,
10865             (opt.duration || defaultDur) || .35,
10866             (opt.easing || defaultEase) || 'easeOut',
10867             function(){
10868                 Roo.callback(cb, this);
10869             },
10870             this
10871         );
10872         opt.anim = anim;
10873         return anim;
10874     }
10875 };
10876
10877 // backwords compat
10878 Roo.Fx.resize = Roo.Fx.scale;
10879
10880 //When included, Roo.Fx is automatically applied to Element so that all basic
10881 //effects are available directly via the Element API
10882 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10883  * Based on:
10884  * Ext JS Library 1.1.1
10885  * Copyright(c) 2006-2007, Ext JS, LLC.
10886  *
10887  * Originally Released Under LGPL - original licence link has changed is not relivant.
10888  *
10889  * Fork - LGPL
10890  * <script type="text/javascript">
10891  */
10892
10893
10894 /**
10895  * @class Roo.CompositeElement
10896  * Standard composite class. Creates a Roo.Element for every element in the collection.
10897  * <br><br>
10898  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10899  * actions will be performed on all the elements in this collection.</b>
10900  * <br><br>
10901  * All methods return <i>this</i> and can be chained.
10902  <pre><code>
10903  var els = Roo.select("#some-el div.some-class", true);
10904  // or select directly from an existing element
10905  var el = Roo.get('some-el');
10906  el.select('div.some-class', true);
10907
10908  els.setWidth(100); // all elements become 100 width
10909  els.hide(true); // all elements fade out and hide
10910  // or
10911  els.setWidth(100).hide(true);
10912  </code></pre>
10913  */
10914 Roo.CompositeElement = function(els){
10915     this.elements = [];
10916     this.addElements(els);
10917 };
10918 Roo.CompositeElement.prototype = {
10919     isComposite: true,
10920     addElements : function(els){
10921         if(!els) return this;
10922         if(typeof els == "string"){
10923             els = Roo.Element.selectorFunction(els);
10924         }
10925         var yels = this.elements;
10926         var index = yels.length-1;
10927         for(var i = 0, len = els.length; i < len; i++) {
10928                 yels[++index] = Roo.get(els[i]);
10929         }
10930         return this;
10931     },
10932
10933     /**
10934     * Clears this composite and adds the elements returned by the passed selector.
10935     * @param {String/Array} els A string CSS selector, an array of elements or an element
10936     * @return {CompositeElement} this
10937     */
10938     fill : function(els){
10939         this.elements = [];
10940         this.add(els);
10941         return this;
10942     },
10943
10944     /**
10945     * Filters this composite to only elements that match the passed selector.
10946     * @param {String} selector A string CSS selector
10947     * @return {CompositeElement} this
10948     */
10949     filter : function(selector){
10950         var els = [];
10951         this.each(function(el){
10952             if(el.is(selector)){
10953                 els[els.length] = el.dom;
10954             }
10955         });
10956         this.fill(els);
10957         return this;
10958     },
10959
10960     invoke : function(fn, args){
10961         var els = this.elements;
10962         for(var i = 0, len = els.length; i < len; i++) {
10963                 Roo.Element.prototype[fn].apply(els[i], args);
10964         }
10965         return this;
10966     },
10967     /**
10968     * Adds elements to this composite.
10969     * @param {String/Array} els A string CSS selector, an array of elements or an element
10970     * @return {CompositeElement} this
10971     */
10972     add : function(els){
10973         if(typeof els == "string"){
10974             this.addElements(Roo.Element.selectorFunction(els));
10975         }else if(els.length !== undefined){
10976             this.addElements(els);
10977         }else{
10978             this.addElements([els]);
10979         }
10980         return this;
10981     },
10982     /**
10983     * Calls the passed function passing (el, this, index) for each element in this composite.
10984     * @param {Function} fn The function to call
10985     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10986     * @return {CompositeElement} this
10987     */
10988     each : function(fn, scope){
10989         var els = this.elements;
10990         for(var i = 0, len = els.length; i < len; i++){
10991             if(fn.call(scope || els[i], els[i], this, i) === false) {
10992                 break;
10993             }
10994         }
10995         return this;
10996     },
10997
10998     /**
10999      * Returns the Element object at the specified index
11000      * @param {Number} index
11001      * @return {Roo.Element}
11002      */
11003     item : function(index){
11004         return this.elements[index] || null;
11005     },
11006
11007     /**
11008      * Returns the first Element
11009      * @return {Roo.Element}
11010      */
11011     first : function(){
11012         return this.item(0);
11013     },
11014
11015     /**
11016      * Returns the last Element
11017      * @return {Roo.Element}
11018      */
11019     last : function(){
11020         return this.item(this.elements.length-1);
11021     },
11022
11023     /**
11024      * Returns the number of elements in this composite
11025      * @return Number
11026      */
11027     getCount : function(){
11028         return this.elements.length;
11029     },
11030
11031     /**
11032      * Returns true if this composite contains the passed element
11033      * @return Boolean
11034      */
11035     contains : function(el){
11036         return this.indexOf(el) !== -1;
11037     },
11038
11039     /**
11040      * Returns true if this composite contains the passed element
11041      * @return Boolean
11042      */
11043     indexOf : function(el){
11044         return this.elements.indexOf(Roo.get(el));
11045     },
11046
11047
11048     /**
11049     * Removes the specified element(s).
11050     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11051     * or an array of any of those.
11052     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11053     * @return {CompositeElement} this
11054     */
11055     removeElement : function(el, removeDom){
11056         if(el instanceof Array){
11057             for(var i = 0, len = el.length; i < len; i++){
11058                 this.removeElement(el[i]);
11059             }
11060             return this;
11061         }
11062         var index = typeof el == 'number' ? el : this.indexOf(el);
11063         if(index !== -1){
11064             if(removeDom){
11065                 var d = this.elements[index];
11066                 if(d.dom){
11067                     d.remove();
11068                 }else{
11069                     d.parentNode.removeChild(d);
11070                 }
11071             }
11072             this.elements.splice(index, 1);
11073         }
11074         return this;
11075     },
11076
11077     /**
11078     * Replaces the specified element with the passed element.
11079     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11080     * to replace.
11081     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11082     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11083     * @return {CompositeElement} this
11084     */
11085     replaceElement : function(el, replacement, domReplace){
11086         var index = typeof el == 'number' ? el : this.indexOf(el);
11087         if(index !== -1){
11088             if(domReplace){
11089                 this.elements[index].replaceWith(replacement);
11090             }else{
11091                 this.elements.splice(index, 1, Roo.get(replacement))
11092             }
11093         }
11094         return this;
11095     },
11096
11097     /**
11098      * Removes all elements.
11099      */
11100     clear : function(){
11101         this.elements = [];
11102     }
11103 };
11104 (function(){
11105     Roo.CompositeElement.createCall = function(proto, fnName){
11106         if(!proto[fnName]){
11107             proto[fnName] = function(){
11108                 return this.invoke(fnName, arguments);
11109             };
11110         }
11111     };
11112     for(var fnName in Roo.Element.prototype){
11113         if(typeof Roo.Element.prototype[fnName] == "function"){
11114             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11115         }
11116     };
11117 })();
11118 /*
11119  * Based on:
11120  * Ext JS Library 1.1.1
11121  * Copyright(c) 2006-2007, Ext JS, LLC.
11122  *
11123  * Originally Released Under LGPL - original licence link has changed is not relivant.
11124  *
11125  * Fork - LGPL
11126  * <script type="text/javascript">
11127  */
11128
11129 /**
11130  * @class Roo.CompositeElementLite
11131  * @extends Roo.CompositeElement
11132  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11133  <pre><code>
11134  var els = Roo.select("#some-el div.some-class");
11135  // or select directly from an existing element
11136  var el = Roo.get('some-el');
11137  el.select('div.some-class');
11138
11139  els.setWidth(100); // all elements become 100 width
11140  els.hide(true); // all elements fade out and hide
11141  // or
11142  els.setWidth(100).hide(true);
11143  </code></pre><br><br>
11144  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11145  * actions will be performed on all the elements in this collection.</b>
11146  */
11147 Roo.CompositeElementLite = function(els){
11148     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11149     this.el = new Roo.Element.Flyweight();
11150 };
11151 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11152     addElements : function(els){
11153         if(els){
11154             if(els instanceof Array){
11155                 this.elements = this.elements.concat(els);
11156             }else{
11157                 var yels = this.elements;
11158                 var index = yels.length-1;
11159                 for(var i = 0, len = els.length; i < len; i++) {
11160                     yels[++index] = els[i];
11161                 }
11162             }
11163         }
11164         return this;
11165     },
11166     invoke : function(fn, args){
11167         var els = this.elements;
11168         var el = this.el;
11169         for(var i = 0, len = els.length; i < len; i++) {
11170             el.dom = els[i];
11171                 Roo.Element.prototype[fn].apply(el, args);
11172         }
11173         return this;
11174     },
11175     /**
11176      * Returns a flyweight Element of the dom element object at the specified index
11177      * @param {Number} index
11178      * @return {Roo.Element}
11179      */
11180     item : function(index){
11181         if(!this.elements[index]){
11182             return null;
11183         }
11184         this.el.dom = this.elements[index];
11185         return this.el;
11186     },
11187
11188     // fixes scope with flyweight
11189     addListener : function(eventName, handler, scope, opt){
11190         var els = this.elements;
11191         for(var i = 0, len = els.length; i < len; i++) {
11192             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11193         }
11194         return this;
11195     },
11196
11197     /**
11198     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11199     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11200     * a reference to the dom node, use el.dom.</b>
11201     * @param {Function} fn The function to call
11202     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11203     * @return {CompositeElement} this
11204     */
11205     each : function(fn, scope){
11206         var els = this.elements;
11207         var el = this.el;
11208         for(var i = 0, len = els.length; i < len; i++){
11209             el.dom = els[i];
11210                 if(fn.call(scope || el, el, this, i) === false){
11211                 break;
11212             }
11213         }
11214         return this;
11215     },
11216
11217     indexOf : function(el){
11218         return this.elements.indexOf(Roo.getDom(el));
11219     },
11220
11221     replaceElement : function(el, replacement, domReplace){
11222         var index = typeof el == 'number' ? el : this.indexOf(el);
11223         if(index !== -1){
11224             replacement = Roo.getDom(replacement);
11225             if(domReplace){
11226                 var d = this.elements[index];
11227                 d.parentNode.insertBefore(replacement, d);
11228                 d.parentNode.removeChild(d);
11229             }
11230             this.elements.splice(index, 1, replacement);
11231         }
11232         return this;
11233     }
11234 });
11235 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11236
11237 /*
11238  * Based on:
11239  * Ext JS Library 1.1.1
11240  * Copyright(c) 2006-2007, Ext JS, LLC.
11241  *
11242  * Originally Released Under LGPL - original licence link has changed is not relivant.
11243  *
11244  * Fork - LGPL
11245  * <script type="text/javascript">
11246  */
11247
11248  
11249
11250 /**
11251  * @class Roo.data.Connection
11252  * @extends Roo.util.Observable
11253  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11254  * either to a configured URL, or to a URL specified at request time.<br><br>
11255  * <p>
11256  * Requests made by this class are asynchronous, and will return immediately. No data from
11257  * the server will be available to the statement immediately following the {@link #request} call.
11258  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11259  * <p>
11260  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11261  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11262  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11263  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11264  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11265  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11266  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11267  * standard DOM methods.
11268  * @constructor
11269  * @param {Object} config a configuration object.
11270  */
11271 Roo.data.Connection = function(config){
11272     Roo.apply(this, config);
11273     this.addEvents({
11274         /**
11275          * @event beforerequest
11276          * Fires before a network request is made to retrieve a data object.
11277          * @param {Connection} conn This Connection object.
11278          * @param {Object} options The options config object passed to the {@link #request} method.
11279          */
11280         "beforerequest" : true,
11281         /**
11282          * @event requestcomplete
11283          * Fires if the request was successfully completed.
11284          * @param {Connection} conn This Connection object.
11285          * @param {Object} response The XHR object containing the response data.
11286          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11287          * @param {Object} options The options config object passed to the {@link #request} method.
11288          */
11289         "requestcomplete" : true,
11290         /**
11291          * @event requestexception
11292          * Fires if an error HTTP status was returned from the server.
11293          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11294          * @param {Connection} conn This Connection object.
11295          * @param {Object} response The XHR object containing the response data.
11296          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11297          * @param {Object} options The options config object passed to the {@link #request} method.
11298          */
11299         "requestexception" : true
11300     });
11301     Roo.data.Connection.superclass.constructor.call(this);
11302 };
11303
11304 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11305     /**
11306      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11307      */
11308     /**
11309      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11310      * extra parameters to each request made by this object. (defaults to undefined)
11311      */
11312     /**
11313      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11314      *  to each request made by this object. (defaults to undefined)
11315      */
11316     /**
11317      * @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)
11318      */
11319     /**
11320      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11321      */
11322     timeout : 30000,
11323     /**
11324      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11325      * @type Boolean
11326      */
11327     autoAbort:false,
11328
11329     /**
11330      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11331      * @type Boolean
11332      */
11333     disableCaching: true,
11334
11335     /**
11336      * Sends an HTTP request to a remote server.
11337      * @param {Object} options An object which may contain the following properties:<ul>
11338      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11339      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11340      * request, a url encoded string or a function to call to get either.</li>
11341      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11342      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11343      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11344      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11345      * <li>options {Object} The parameter to the request call.</li>
11346      * <li>success {Boolean} True if the request succeeded.</li>
11347      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11348      * </ul></li>
11349      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11350      * The callback is passed the following parameters:<ul>
11351      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11352      * <li>options {Object} The parameter to the request call.</li>
11353      * </ul></li>
11354      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11355      * The callback is passed the following parameters:<ul>
11356      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11357      * <li>options {Object} The parameter to the request call.</li>
11358      * </ul></li>
11359      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11360      * for the callback function. Defaults to the browser window.</li>
11361      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11362      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11363      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11364      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11365      * params for the post data. Any params will be appended to the URL.</li>
11366      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11367      * </ul>
11368      * @return {Number} transactionId
11369      */
11370     request : function(o){
11371         if(this.fireEvent("beforerequest", this, o) !== false){
11372             var p = o.params;
11373
11374             if(typeof p == "function"){
11375                 p = p.call(o.scope||window, o);
11376             }
11377             if(typeof p == "object"){
11378                 p = Roo.urlEncode(o.params);
11379             }
11380             if(this.extraParams){
11381                 var extras = Roo.urlEncode(this.extraParams);
11382                 p = p ? (p + '&' + extras) : extras;
11383             }
11384
11385             var url = o.url || this.url;
11386             if(typeof url == 'function'){
11387                 url = url.call(o.scope||window, o);
11388             }
11389
11390             if(o.form){
11391                 var form = Roo.getDom(o.form);
11392                 url = url || form.action;
11393
11394                 var enctype = form.getAttribute("enctype");
11395                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11396                     return this.doFormUpload(o, p, url);
11397                 }
11398                 var f = Roo.lib.Ajax.serializeForm(form);
11399                 p = p ? (p + '&' + f) : f;
11400             }
11401
11402             var hs = o.headers;
11403             if(this.defaultHeaders){
11404                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11405                 if(!o.headers){
11406                     o.headers = hs;
11407                 }
11408             }
11409
11410             var cb = {
11411                 success: this.handleResponse,
11412                 failure: this.handleFailure,
11413                 scope: this,
11414                 argument: {options: o},
11415                 timeout : o.timeout || this.timeout
11416             };
11417
11418             var method = o.method||this.method||(p ? "POST" : "GET");
11419
11420             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11421                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11422             }
11423
11424             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11425                 if(o.autoAbort){
11426                     this.abort();
11427                 }
11428             }else if(this.autoAbort !== false){
11429                 this.abort();
11430             }
11431
11432             if((method == 'GET' && p) || o.xmlData){
11433                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11434                 p = '';
11435             }
11436             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11437             return this.transId;
11438         }else{
11439             Roo.callback(o.callback, o.scope, [o, null, null]);
11440             return null;
11441         }
11442     },
11443
11444     /**
11445      * Determine whether this object has a request outstanding.
11446      * @param {Number} transactionId (Optional) defaults to the last transaction
11447      * @return {Boolean} True if there is an outstanding request.
11448      */
11449     isLoading : function(transId){
11450         if(transId){
11451             return Roo.lib.Ajax.isCallInProgress(transId);
11452         }else{
11453             return this.transId ? true : false;
11454         }
11455     },
11456
11457     /**
11458      * Aborts any outstanding request.
11459      * @param {Number} transactionId (Optional) defaults to the last transaction
11460      */
11461     abort : function(transId){
11462         if(transId || this.isLoading()){
11463             Roo.lib.Ajax.abort(transId || this.transId);
11464         }
11465     },
11466
11467     // private
11468     handleResponse : function(response){
11469         this.transId = false;
11470         var options = response.argument.options;
11471         response.argument = options ? options.argument : null;
11472         this.fireEvent("requestcomplete", this, response, options);
11473         Roo.callback(options.success, options.scope, [response, options]);
11474         Roo.callback(options.callback, options.scope, [options, true, response]);
11475     },
11476
11477     // private
11478     handleFailure : function(response, e){
11479         this.transId = false;
11480         var options = response.argument.options;
11481         response.argument = options ? options.argument : null;
11482         this.fireEvent("requestexception", this, response, options, e);
11483         Roo.callback(options.failure, options.scope, [response, options]);
11484         Roo.callback(options.callback, options.scope, [options, false, response]);
11485     },
11486
11487     // private
11488     doFormUpload : function(o, ps, url){
11489         var id = Roo.id();
11490         var frame = document.createElement('iframe');
11491         frame.id = id;
11492         frame.name = id;
11493         frame.className = 'x-hidden';
11494         if(Roo.isIE){
11495             frame.src = Roo.SSL_SECURE_URL;
11496         }
11497         document.body.appendChild(frame);
11498
11499         if(Roo.isIE){
11500            document.frames[id].name = id;
11501         }
11502
11503         var form = Roo.getDom(o.form);
11504         form.target = id;
11505         form.method = 'POST';
11506         form.enctype = form.encoding = 'multipart/form-data';
11507         if(url){
11508             form.action = url;
11509         }
11510
11511         var hiddens, hd;
11512         if(ps){ // add dynamic params
11513             hiddens = [];
11514             ps = Roo.urlDecode(ps, false);
11515             for(var k in ps){
11516                 if(ps.hasOwnProperty(k)){
11517                     hd = document.createElement('input');
11518                     hd.type = 'hidden';
11519                     hd.name = k;
11520                     hd.value = ps[k];
11521                     form.appendChild(hd);
11522                     hiddens.push(hd);
11523                 }
11524             }
11525         }
11526
11527         function cb(){
11528             var r = {  // bogus response object
11529                 responseText : '',
11530                 responseXML : null
11531             };
11532
11533             r.argument = o ? o.argument : null;
11534
11535             try { //
11536                 var doc;
11537                 if(Roo.isIE){
11538                     doc = frame.contentWindow.document;
11539                 }else {
11540                     doc = (frame.contentDocument || window.frames[id].document);
11541                 }
11542                 if(doc && doc.body){
11543                     r.responseText = doc.body.innerHTML;
11544                 }
11545                 if(doc && doc.XMLDocument){
11546                     r.responseXML = doc.XMLDocument;
11547                 }else {
11548                     r.responseXML = doc;
11549                 }
11550             }
11551             catch(e) {
11552                 // ignore
11553             }
11554
11555             Roo.EventManager.removeListener(frame, 'load', cb, this);
11556
11557             this.fireEvent("requestcomplete", this, r, o);
11558             Roo.callback(o.success, o.scope, [r, o]);
11559             Roo.callback(o.callback, o.scope, [o, true, r]);
11560
11561             setTimeout(function(){document.body.removeChild(frame);}, 100);
11562         }
11563
11564         Roo.EventManager.on(frame, 'load', cb, this);
11565         form.submit();
11566
11567         if(hiddens){ // remove dynamic params
11568             for(var i = 0, len = hiddens.length; i < len; i++){
11569                 form.removeChild(hiddens[i]);
11570             }
11571         }
11572     }
11573 });
11574 /*
11575  * Based on:
11576  * Ext JS Library 1.1.1
11577  * Copyright(c) 2006-2007, Ext JS, LLC.
11578  *
11579  * Originally Released Under LGPL - original licence link has changed is not relivant.
11580  *
11581  * Fork - LGPL
11582  * <script type="text/javascript">
11583  */
11584  
11585 /**
11586  * Global Ajax request class.
11587  * 
11588  * @class Roo.Ajax
11589  * @extends Roo.data.Connection
11590  * @static
11591  * 
11592  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11593  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11594  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11595  * @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)
11596  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11597  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11598  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11599  */
11600 Roo.Ajax = new Roo.data.Connection({
11601     // fix up the docs
11602     /**
11603      * @scope Roo.Ajax
11604      * @type {Boolear} 
11605      */
11606     autoAbort : false,
11607
11608     /**
11609      * Serialize the passed form into a url encoded string
11610      * @scope Roo.Ajax
11611      * @param {String/HTMLElement} form
11612      * @return {String}
11613      */
11614     serializeForm : function(form){
11615         return Roo.lib.Ajax.serializeForm(form);
11616     }
11617 });/*
11618  * Based on:
11619  * Ext JS Library 1.1.1
11620  * Copyright(c) 2006-2007, Ext JS, LLC.
11621  *
11622  * Originally Released Under LGPL - original licence link has changed is not relivant.
11623  *
11624  * Fork - LGPL
11625  * <script type="text/javascript">
11626  */
11627
11628  
11629 /**
11630  * @class Roo.UpdateManager
11631  * @extends Roo.util.Observable
11632  * Provides AJAX-style update for Element object.<br><br>
11633  * Usage:<br>
11634  * <pre><code>
11635  * // Get it from a Roo.Element object
11636  * var el = Roo.get("foo");
11637  * var mgr = el.getUpdateManager();
11638  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11639  * ...
11640  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11641  * <br>
11642  * // or directly (returns the same UpdateManager instance)
11643  * var mgr = new Roo.UpdateManager("myElementId");
11644  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11645  * mgr.on("update", myFcnNeedsToKnow);
11646  * <br>
11647    // short handed call directly from the element object
11648    Roo.get("foo").load({
11649         url: "bar.php",
11650         scripts:true,
11651         params: "for=bar",
11652         text: "Loading Foo..."
11653    });
11654  * </code></pre>
11655  * @constructor
11656  * Create new UpdateManager directly.
11657  * @param {String/HTMLElement/Roo.Element} el The element to update
11658  * @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).
11659  */
11660 Roo.UpdateManager = function(el, forceNew){
11661     el = Roo.get(el);
11662     if(!forceNew && el.updateManager){
11663         return el.updateManager;
11664     }
11665     /**
11666      * The Element object
11667      * @type Roo.Element
11668      */
11669     this.el = el;
11670     /**
11671      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11672      * @type String
11673      */
11674     this.defaultUrl = null;
11675
11676     this.addEvents({
11677         /**
11678          * @event beforeupdate
11679          * Fired before an update is made, return false from your handler and the update is cancelled.
11680          * @param {Roo.Element} el
11681          * @param {String/Object/Function} url
11682          * @param {String/Object} params
11683          */
11684         "beforeupdate": true,
11685         /**
11686          * @event update
11687          * Fired after successful update is made.
11688          * @param {Roo.Element} el
11689          * @param {Object} oResponseObject The response Object
11690          */
11691         "update": true,
11692         /**
11693          * @event failure
11694          * Fired on update failure.
11695          * @param {Roo.Element} el
11696          * @param {Object} oResponseObject The response Object
11697          */
11698         "failure": true
11699     });
11700     var d = Roo.UpdateManager.defaults;
11701     /**
11702      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11703      * @type String
11704      */
11705     this.sslBlankUrl = d.sslBlankUrl;
11706     /**
11707      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11708      * @type Boolean
11709      */
11710     this.disableCaching = d.disableCaching;
11711     /**
11712      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11713      * @type String
11714      */
11715     this.indicatorText = d.indicatorText;
11716     /**
11717      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11718      * @type String
11719      */
11720     this.showLoadIndicator = d.showLoadIndicator;
11721     /**
11722      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11723      * @type Number
11724      */
11725     this.timeout = d.timeout;
11726
11727     /**
11728      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11729      * @type Boolean
11730      */
11731     this.loadScripts = d.loadScripts;
11732
11733     /**
11734      * Transaction object of current executing transaction
11735      */
11736     this.transaction = null;
11737
11738     /**
11739      * @private
11740      */
11741     this.autoRefreshProcId = null;
11742     /**
11743      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11744      * @type Function
11745      */
11746     this.refreshDelegate = this.refresh.createDelegate(this);
11747     /**
11748      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11749      * @type Function
11750      */
11751     this.updateDelegate = this.update.createDelegate(this);
11752     /**
11753      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11754      * @type Function
11755      */
11756     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11757     /**
11758      * @private
11759      */
11760     this.successDelegate = this.processSuccess.createDelegate(this);
11761     /**
11762      * @private
11763      */
11764     this.failureDelegate = this.processFailure.createDelegate(this);
11765
11766     if(!this.renderer){
11767      /**
11768       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11769       */
11770     this.renderer = new Roo.UpdateManager.BasicRenderer();
11771     }
11772     
11773     Roo.UpdateManager.superclass.constructor.call(this);
11774 };
11775
11776 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11777     /**
11778      * Get the Element this UpdateManager is bound to
11779      * @return {Roo.Element} The element
11780      */
11781     getEl : function(){
11782         return this.el;
11783     },
11784     /**
11785      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11786      * @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:
11787 <pre><code>
11788 um.update({<br/>
11789     url: "your-url.php",<br/>
11790     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11791     callback: yourFunction,<br/>
11792     scope: yourObject, //(optional scope)  <br/>
11793     discardUrl: false, <br/>
11794     nocache: false,<br/>
11795     text: "Loading...",<br/>
11796     timeout: 30,<br/>
11797     scripts: false<br/>
11798 });
11799 </code></pre>
11800      * The only required property is url. The optional properties nocache, text and scripts
11801      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11802      * @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}
11803      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11804      * @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.
11805      */
11806     update : function(url, params, callback, discardUrl){
11807         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11808             var method = this.method,
11809                 cfg;
11810             if(typeof url == "object"){ // must be config object
11811                 cfg = url;
11812                 url = cfg.url;
11813                 params = params || cfg.params;
11814                 callback = callback || cfg.callback;
11815                 discardUrl = discardUrl || cfg.discardUrl;
11816                 if(callback && cfg.scope){
11817                     callback = callback.createDelegate(cfg.scope);
11818                 }
11819                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11820                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11821                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11822                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11823                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11824             }
11825             this.showLoading();
11826             if(!discardUrl){
11827                 this.defaultUrl = url;
11828             }
11829             if(typeof url == "function"){
11830                 url = url.call(this);
11831             }
11832
11833             method = method || (params ? "POST" : "GET");
11834             if(method == "GET"){
11835                 url = this.prepareUrl(url);
11836             }
11837
11838             var o = Roo.apply(cfg ||{}, {
11839                 url : url,
11840                 params: params,
11841                 success: this.successDelegate,
11842                 failure: this.failureDelegate,
11843                 callback: undefined,
11844                 timeout: (this.timeout*1000),
11845                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11846             });
11847             Roo.log("updated manager called with timeout of " + o.timeout);
11848             this.transaction = Roo.Ajax.request(o);
11849         }
11850     },
11851
11852     /**
11853      * 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.
11854      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11855      * @param {String/HTMLElement} form The form Id or form element
11856      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11857      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11858      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11859      */
11860     formUpdate : function(form, url, reset, callback){
11861         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11862             if(typeof url == "function"){
11863                 url = url.call(this);
11864             }
11865             form = Roo.getDom(form);
11866             this.transaction = Roo.Ajax.request({
11867                 form: form,
11868                 url:url,
11869                 success: this.successDelegate,
11870                 failure: this.failureDelegate,
11871                 timeout: (this.timeout*1000),
11872                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11873             });
11874             this.showLoading.defer(1, this);
11875         }
11876     },
11877
11878     /**
11879      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11880      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11881      */
11882     refresh : function(callback){
11883         if(this.defaultUrl == null){
11884             return;
11885         }
11886         this.update(this.defaultUrl, null, callback, true);
11887     },
11888
11889     /**
11890      * Set this element to auto refresh.
11891      * @param {Number} interval How often to update (in seconds).
11892      * @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)
11893      * @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}
11894      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11895      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11896      */
11897     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11898         if(refreshNow){
11899             this.update(url || this.defaultUrl, params, callback, true);
11900         }
11901         if(this.autoRefreshProcId){
11902             clearInterval(this.autoRefreshProcId);
11903         }
11904         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11905     },
11906
11907     /**
11908      * Stop auto refresh on this element.
11909      */
11910      stopAutoRefresh : function(){
11911         if(this.autoRefreshProcId){
11912             clearInterval(this.autoRefreshProcId);
11913             delete this.autoRefreshProcId;
11914         }
11915     },
11916
11917     isAutoRefreshing : function(){
11918        return this.autoRefreshProcId ? true : false;
11919     },
11920     /**
11921      * Called to update the element to "Loading" state. Override to perform custom action.
11922      */
11923     showLoading : function(){
11924         if(this.showLoadIndicator){
11925             this.el.update(this.indicatorText);
11926         }
11927     },
11928
11929     /**
11930      * Adds unique parameter to query string if disableCaching = true
11931      * @private
11932      */
11933     prepareUrl : function(url){
11934         if(this.disableCaching){
11935             var append = "_dc=" + (new Date().getTime());
11936             if(url.indexOf("?") !== -1){
11937                 url += "&" + append;
11938             }else{
11939                 url += "?" + append;
11940             }
11941         }
11942         return url;
11943     },
11944
11945     /**
11946      * @private
11947      */
11948     processSuccess : function(response){
11949         this.transaction = null;
11950         if(response.argument.form && response.argument.reset){
11951             try{ // put in try/catch since some older FF releases had problems with this
11952                 response.argument.form.reset();
11953             }catch(e){}
11954         }
11955         if(this.loadScripts){
11956             this.renderer.render(this.el, response, this,
11957                 this.updateComplete.createDelegate(this, [response]));
11958         }else{
11959             this.renderer.render(this.el, response, this);
11960             this.updateComplete(response);
11961         }
11962     },
11963
11964     updateComplete : function(response){
11965         this.fireEvent("update", this.el, response);
11966         if(typeof response.argument.callback == "function"){
11967             response.argument.callback(this.el, true, response);
11968         }
11969     },
11970
11971     /**
11972      * @private
11973      */
11974     processFailure : function(response){
11975         this.transaction = null;
11976         this.fireEvent("failure", this.el, response);
11977         if(typeof response.argument.callback == "function"){
11978             response.argument.callback(this.el, false, response);
11979         }
11980     },
11981
11982     /**
11983      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11984      * @param {Object} renderer The object implementing the render() method
11985      */
11986     setRenderer : function(renderer){
11987         this.renderer = renderer;
11988     },
11989
11990     getRenderer : function(){
11991        return this.renderer;
11992     },
11993
11994     /**
11995      * Set the defaultUrl used for updates
11996      * @param {String/Function} defaultUrl The url or a function to call to get the url
11997      */
11998     setDefaultUrl : function(defaultUrl){
11999         this.defaultUrl = defaultUrl;
12000     },
12001
12002     /**
12003      * Aborts the executing transaction
12004      */
12005     abort : function(){
12006         if(this.transaction){
12007             Roo.Ajax.abort(this.transaction);
12008         }
12009     },
12010
12011     /**
12012      * Returns true if an update is in progress
12013      * @return {Boolean}
12014      */
12015     isUpdating : function(){
12016         if(this.transaction){
12017             return Roo.Ajax.isLoading(this.transaction);
12018         }
12019         return false;
12020     }
12021 });
12022
12023 /**
12024  * @class Roo.UpdateManager.defaults
12025  * @static (not really - but it helps the doc tool)
12026  * The defaults collection enables customizing the default properties of UpdateManager
12027  */
12028    Roo.UpdateManager.defaults = {
12029        /**
12030          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12031          * @type Number
12032          */
12033          timeout : 30,
12034
12035          /**
12036          * True to process scripts by default (Defaults to false).
12037          * @type Boolean
12038          */
12039         loadScripts : false,
12040
12041         /**
12042         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12043         * @type String
12044         */
12045         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12046         /**
12047          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12048          * @type Boolean
12049          */
12050         disableCaching : false,
12051         /**
12052          * Whether to show indicatorText when loading (Defaults to true).
12053          * @type Boolean
12054          */
12055         showLoadIndicator : true,
12056         /**
12057          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12058          * @type String
12059          */
12060         indicatorText : '<div class="loading-indicator">Loading...</div>'
12061    };
12062
12063 /**
12064  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12065  *Usage:
12066  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12067  * @param {String/HTMLElement/Roo.Element} el The element to update
12068  * @param {String} url The url
12069  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12070  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12071  * @static
12072  * @deprecated
12073  * @member Roo.UpdateManager
12074  */
12075 Roo.UpdateManager.updateElement = function(el, url, params, options){
12076     var um = Roo.get(el, true).getUpdateManager();
12077     Roo.apply(um, options);
12078     um.update(url, params, options ? options.callback : null);
12079 };
12080 // alias for backwards compat
12081 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12082 /**
12083  * @class Roo.UpdateManager.BasicRenderer
12084  * Default Content renderer. Updates the elements innerHTML with the responseText.
12085  */
12086 Roo.UpdateManager.BasicRenderer = function(){};
12087
12088 Roo.UpdateManager.BasicRenderer.prototype = {
12089     /**
12090      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12091      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12092      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12093      * @param {Roo.Element} el The element being rendered
12094      * @param {Object} response The YUI Connect response object
12095      * @param {UpdateManager} updateManager The calling update manager
12096      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12097      */
12098      render : function(el, response, updateManager, callback){
12099         el.update(response.responseText, updateManager.loadScripts, callback);
12100     }
12101 };
12102 /*
12103  * Based on:
12104  * Roo JS
12105  * (c)) Alan Knowles
12106  * Licence : LGPL
12107  */
12108
12109
12110 /**
12111  * @class Roo.DomTemplate
12112  * @extends Roo.Template
12113  * An effort at a dom based template engine..
12114  *
12115  * Similar to XTemplate, except it uses dom parsing to create the template..
12116  *
12117  * Supported features:
12118  *
12119  *  Tags:
12120
12121 <pre><code>
12122       {a_variable} - output encoded.
12123       {a_variable.format:("Y-m-d")} - call a method on the variable
12124       {a_variable:raw} - unencoded output
12125       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12126       {a_variable:this.method_on_template(...)} - call a method on the template object.
12127  
12128 </code></pre>
12129  *  The tpl tag:
12130 <pre><code>
12131         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12132         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12133         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12134         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12135   
12136 </code></pre>
12137  *      
12138  */
12139 Roo.DomTemplate = function()
12140 {
12141      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12142      if (this.html) {
12143         this.compile();
12144      }
12145 };
12146
12147
12148 Roo.extend(Roo.DomTemplate, Roo.Template, {
12149     /**
12150      * id counter for sub templates.
12151      */
12152     id : 0,
12153     /**
12154      * flag to indicate if dom parser is inside a pre,
12155      * it will strip whitespace if not.
12156      */
12157     inPre : false,
12158     
12159     /**
12160      * The various sub templates
12161      */
12162     tpls : false,
12163     
12164     
12165     
12166     /**
12167      *
12168      * basic tag replacing syntax
12169      * WORD:WORD()
12170      *
12171      * // you can fake an object call by doing this
12172      *  x.t:(test,tesT) 
12173      * 
12174      */
12175     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12176     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12177     
12178     iterChild : function (node, method) {
12179         
12180         var oldPre = this.inPre;
12181         if (node.tagName == 'PRE') {
12182             this.inPre = true;
12183         }
12184         for( var i = 0; i < node.childNodes.length; i++) {
12185             method.call(this, node.childNodes[i]);
12186         }
12187         this.inPre = oldPre;
12188     },
12189     
12190     
12191     
12192     /**
12193      * compile the template
12194      *
12195      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12196      *
12197      */
12198     compile: function()
12199     {
12200         var s = this.html;
12201         
12202         // covert the html into DOM...
12203         var doc = false;
12204         var div =false;
12205         try {
12206             doc = document.implementation.createHTMLDocument("");
12207             doc.documentElement.innerHTML =   this.html  ;
12208             div = doc.documentElement;
12209         } catch (e) {
12210             // old IE... - nasty -- it causes all sorts of issues.. with
12211             // images getting pulled from server..
12212             div = document.createElement('div');
12213             div.innerHTML = this.html;
12214         }
12215         //doc.documentElement.innerHTML = htmlBody
12216          
12217         
12218         
12219         this.tpls = [];
12220         var _t = this;
12221         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12222         
12223         var tpls = this.tpls;
12224         
12225         // create a top level template from the snippet..
12226         
12227         //Roo.log(div.innerHTML);
12228         
12229         var tpl = {
12230             uid : 'master',
12231             id : this.id++,
12232             attr : false,
12233             value : false,
12234             body : div.innerHTML,
12235             
12236             forCall : false,
12237             execCall : false,
12238             dom : div,
12239             isTop : true
12240             
12241         };
12242         tpls.unshift(tpl);
12243         
12244         
12245         // compile them...
12246         this.tpls = [];
12247         Roo.each(tpls, function(tp){
12248             this.compileTpl(tp);
12249             this.tpls[tp.id] = tp;
12250         }, this);
12251         
12252         this.master = tpls[0];
12253         return this;
12254         
12255         
12256     },
12257     
12258     compileNode : function(node, istop) {
12259         // test for
12260         //Roo.log(node);
12261         
12262         
12263         // skip anything not a tag..
12264         if (node.nodeType != 1) {
12265             if (node.nodeType == 3 && !this.inPre) {
12266                 // reduce white space..
12267                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12268                 
12269             }
12270             return;
12271         }
12272         
12273         var tpl = {
12274             uid : false,
12275             id : false,
12276             attr : false,
12277             value : false,
12278             body : '',
12279             
12280             forCall : false,
12281             execCall : false,
12282             dom : false,
12283             isTop : istop
12284             
12285             
12286         };
12287         
12288         
12289         switch(true) {
12290             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12291             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12292             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12293             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12294             // no default..
12295         }
12296         
12297         
12298         if (!tpl.attr) {
12299             // just itterate children..
12300             this.iterChild(node,this.compileNode);
12301             return;
12302         }
12303         tpl.uid = this.id++;
12304         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12305         node.removeAttribute('roo-'+ tpl.attr);
12306         if (tpl.attr != 'name') {
12307             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12308             node.parentNode.replaceChild(placeholder,  node);
12309         } else {
12310             
12311             var placeholder =  document.createElement('span');
12312             placeholder.className = 'roo-tpl-' + tpl.value;
12313             node.parentNode.replaceChild(placeholder,  node);
12314         }
12315         
12316         // parent now sees '{domtplXXXX}
12317         this.iterChild(node,this.compileNode);
12318         
12319         // we should now have node body...
12320         var div = document.createElement('div');
12321         div.appendChild(node);
12322         tpl.dom = node;
12323         // this has the unfortunate side effect of converting tagged attributes
12324         // eg. href="{...}" into %7C...%7D
12325         // this has been fixed by searching for those combo's although it's a bit hacky..
12326         
12327         
12328         tpl.body = div.innerHTML;
12329         
12330         
12331          
12332         tpl.id = tpl.uid;
12333         switch(tpl.attr) {
12334             case 'for' :
12335                 switch (tpl.value) {
12336                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12337                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12338                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12339                 }
12340                 break;
12341             
12342             case 'exec':
12343                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12344                 break;
12345             
12346             case 'if':     
12347                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12348                 break;
12349             
12350             case 'name':
12351                 tpl.id  = tpl.value; // replace non characters???
12352                 break;
12353             
12354         }
12355         
12356         
12357         this.tpls.push(tpl);
12358         
12359         
12360         
12361     },
12362     
12363     
12364     
12365     
12366     /**
12367      * Compile a segment of the template into a 'sub-template'
12368      *
12369      * 
12370      * 
12371      *
12372      */
12373     compileTpl : function(tpl)
12374     {
12375         var fm = Roo.util.Format;
12376         var useF = this.disableFormats !== true;
12377         
12378         var sep = Roo.isGecko ? "+\n" : ",\n";
12379         
12380         var undef = function(str) {
12381             Roo.debug && Roo.log("Property not found :"  + str);
12382             return '';
12383         };
12384           
12385         //Roo.log(tpl.body);
12386         
12387         
12388         
12389         var fn = function(m, lbrace, name, format, args)
12390         {
12391             //Roo.log("ARGS");
12392             //Roo.log(arguments);
12393             args = args ? args.replace(/\\'/g,"'") : args;
12394             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12395             if (typeof(format) == 'undefined') {
12396                 format =  'htmlEncode'; 
12397             }
12398             if (format == 'raw' ) {
12399                 format = false;
12400             }
12401             
12402             if(name.substr(0, 6) == 'domtpl'){
12403                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12404             }
12405             
12406             // build an array of options to determine if value is undefined..
12407             
12408             // basically get 'xxxx.yyyy' then do
12409             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12410             //    (function () { Roo.log("Property not found"); return ''; })() :
12411             //    ......
12412             
12413             var udef_ar = [];
12414             var lookfor = '';
12415             Roo.each(name.split('.'), function(st) {
12416                 lookfor += (lookfor.length ? '.': '') + st;
12417                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12418             });
12419             
12420             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12421             
12422             
12423             if(format && useF){
12424                 
12425                 args = args ? ',' + args : "";
12426                  
12427                 if(format.substr(0, 5) != "this."){
12428                     format = "fm." + format + '(';
12429                 }else{
12430                     format = 'this.call("'+ format.substr(5) + '", ';
12431                     args = ", values";
12432                 }
12433                 
12434                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12435             }
12436              
12437             if (args && args.length) {
12438                 // called with xxyx.yuu:(test,test)
12439                 // change to ()
12440                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12441             }
12442             // raw.. - :raw modifier..
12443             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12444             
12445         };
12446         var body;
12447         // branched to use + in gecko and [].join() in others
12448         if(Roo.isGecko){
12449             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12450                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12451                     "';};};";
12452         }else{
12453             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12454             body.push(tpl.body.replace(/(\r\n|\n)/g,
12455                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12456             body.push("'].join('');};};");
12457             body = body.join('');
12458         }
12459         
12460         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12461        
12462         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12463         eval(body);
12464         
12465         return this;
12466     },
12467      
12468     /**
12469      * same as applyTemplate, except it's done to one of the subTemplates
12470      * when using named templates, you can do:
12471      *
12472      * var str = pl.applySubTemplate('your-name', values);
12473      *
12474      * 
12475      * @param {Number} id of the template
12476      * @param {Object} values to apply to template
12477      * @param {Object} parent (normaly the instance of this object)
12478      */
12479     applySubTemplate : function(id, values, parent)
12480     {
12481         
12482         
12483         var t = this.tpls[id];
12484         
12485         
12486         try { 
12487             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12488                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12489                 return '';
12490             }
12491         } catch(e) {
12492             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12493             Roo.log(values);
12494           
12495             return '';
12496         }
12497         try { 
12498             
12499             if(t.execCall && t.execCall.call(this, values, parent)){
12500                 return '';
12501             }
12502         } catch(e) {
12503             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12504             Roo.log(values);
12505             return '';
12506         }
12507         
12508         try {
12509             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12510             parent = t.target ? values : parent;
12511             if(t.forCall && vs instanceof Array){
12512                 var buf = [];
12513                 for(var i = 0, len = vs.length; i < len; i++){
12514                     try {
12515                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12516                     } catch (e) {
12517                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12518                         Roo.log(e.body);
12519                         //Roo.log(t.compiled);
12520                         Roo.log(vs[i]);
12521                     }   
12522                 }
12523                 return buf.join('');
12524             }
12525         } catch (e) {
12526             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12527             Roo.log(values);
12528             return '';
12529         }
12530         try {
12531             return t.compiled.call(this, vs, parent);
12532         } catch (e) {
12533             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12534             Roo.log(e.body);
12535             //Roo.log(t.compiled);
12536             Roo.log(values);
12537             return '';
12538         }
12539     },
12540
12541    
12542
12543     applyTemplate : function(values){
12544         return this.master.compiled.call(this, values, {});
12545         //var s = this.subs;
12546     },
12547
12548     apply : function(){
12549         return this.applyTemplate.apply(this, arguments);
12550     }
12551
12552  });
12553
12554 Roo.DomTemplate.from = function(el){
12555     el = Roo.getDom(el);
12556     return new Roo.Domtemplate(el.value || el.innerHTML);
12557 };/*
12558  * Based on:
12559  * Ext JS Library 1.1.1
12560  * Copyright(c) 2006-2007, Ext JS, LLC.
12561  *
12562  * Originally Released Under LGPL - original licence link has changed is not relivant.
12563  *
12564  * Fork - LGPL
12565  * <script type="text/javascript">
12566  */
12567
12568 /**
12569  * @class Roo.util.DelayedTask
12570  * Provides a convenient method of performing setTimeout where a new
12571  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12572  * You can use this class to buffer
12573  * the keypress events for a certain number of milliseconds, and perform only if they stop
12574  * for that amount of time.
12575  * @constructor The parameters to this constructor serve as defaults and are not required.
12576  * @param {Function} fn (optional) The default function to timeout
12577  * @param {Object} scope (optional) The default scope of that timeout
12578  * @param {Array} args (optional) The default Array of arguments
12579  */
12580 Roo.util.DelayedTask = function(fn, scope, args){
12581     var id = null, d, t;
12582
12583     var call = function(){
12584         var now = new Date().getTime();
12585         if(now - t >= d){
12586             clearInterval(id);
12587             id = null;
12588             fn.apply(scope, args || []);
12589         }
12590     };
12591     /**
12592      * Cancels any pending timeout and queues a new one
12593      * @param {Number} delay The milliseconds to delay
12594      * @param {Function} newFn (optional) Overrides function passed to constructor
12595      * @param {Object} newScope (optional) Overrides scope passed to constructor
12596      * @param {Array} newArgs (optional) Overrides args passed to constructor
12597      */
12598     this.delay = function(delay, newFn, newScope, newArgs){
12599         if(id && delay != d){
12600             this.cancel();
12601         }
12602         d = delay;
12603         t = new Date().getTime();
12604         fn = newFn || fn;
12605         scope = newScope || scope;
12606         args = newArgs || args;
12607         if(!id){
12608             id = setInterval(call, d);
12609         }
12610     };
12611
12612     /**
12613      * Cancel the last queued timeout
12614      */
12615     this.cancel = function(){
12616         if(id){
12617             clearInterval(id);
12618             id = null;
12619         }
12620     };
12621 };/*
12622  * Based on:
12623  * Ext JS Library 1.1.1
12624  * Copyright(c) 2006-2007, Ext JS, LLC.
12625  *
12626  * Originally Released Under LGPL - original licence link has changed is not relivant.
12627  *
12628  * Fork - LGPL
12629  * <script type="text/javascript">
12630  */
12631  
12632  
12633 Roo.util.TaskRunner = function(interval){
12634     interval = interval || 10;
12635     var tasks = [], removeQueue = [];
12636     var id = 0;
12637     var running = false;
12638
12639     var stopThread = function(){
12640         running = false;
12641         clearInterval(id);
12642         id = 0;
12643     };
12644
12645     var startThread = function(){
12646         if(!running){
12647             running = true;
12648             id = setInterval(runTasks, interval);
12649         }
12650     };
12651
12652     var removeTask = function(task){
12653         removeQueue.push(task);
12654         if(task.onStop){
12655             task.onStop();
12656         }
12657     };
12658
12659     var runTasks = function(){
12660         if(removeQueue.length > 0){
12661             for(var i = 0, len = removeQueue.length; i < len; i++){
12662                 tasks.remove(removeQueue[i]);
12663             }
12664             removeQueue = [];
12665             if(tasks.length < 1){
12666                 stopThread();
12667                 return;
12668             }
12669         }
12670         var now = new Date().getTime();
12671         for(var i = 0, len = tasks.length; i < len; ++i){
12672             var t = tasks[i];
12673             var itime = now - t.taskRunTime;
12674             if(t.interval <= itime){
12675                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12676                 t.taskRunTime = now;
12677                 if(rt === false || t.taskRunCount === t.repeat){
12678                     removeTask(t);
12679                     return;
12680                 }
12681             }
12682             if(t.duration && t.duration <= (now - t.taskStartTime)){
12683                 removeTask(t);
12684             }
12685         }
12686     };
12687
12688     /**
12689      * Queues a new task.
12690      * @param {Object} task
12691      */
12692     this.start = function(task){
12693         tasks.push(task);
12694         task.taskStartTime = new Date().getTime();
12695         task.taskRunTime = 0;
12696         task.taskRunCount = 0;
12697         startThread();
12698         return task;
12699     };
12700
12701     this.stop = function(task){
12702         removeTask(task);
12703         return task;
12704     };
12705
12706     this.stopAll = function(){
12707         stopThread();
12708         for(var i = 0, len = tasks.length; i < len; i++){
12709             if(tasks[i].onStop){
12710                 tasks[i].onStop();
12711             }
12712         }
12713         tasks = [];
12714         removeQueue = [];
12715     };
12716 };
12717
12718 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12719  * Based on:
12720  * Ext JS Library 1.1.1
12721  * Copyright(c) 2006-2007, Ext JS, LLC.
12722  *
12723  * Originally Released Under LGPL - original licence link has changed is not relivant.
12724  *
12725  * Fork - LGPL
12726  * <script type="text/javascript">
12727  */
12728
12729  
12730 /**
12731  * @class Roo.util.MixedCollection
12732  * @extends Roo.util.Observable
12733  * A Collection class that maintains both numeric indexes and keys and exposes events.
12734  * @constructor
12735  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12736  * collection (defaults to false)
12737  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12738  * and return the key value for that item.  This is used when available to look up the key on items that
12739  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12740  * equivalent to providing an implementation for the {@link #getKey} method.
12741  */
12742 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12743     this.items = [];
12744     this.map = {};
12745     this.keys = [];
12746     this.length = 0;
12747     this.addEvents({
12748         /**
12749          * @event clear
12750          * Fires when the collection is cleared.
12751          */
12752         "clear" : true,
12753         /**
12754          * @event add
12755          * Fires when an item is added to the collection.
12756          * @param {Number} index The index at which the item was added.
12757          * @param {Object} o The item added.
12758          * @param {String} key The key associated with the added item.
12759          */
12760         "add" : true,
12761         /**
12762          * @event replace
12763          * Fires when an item is replaced in the collection.
12764          * @param {String} key he key associated with the new added.
12765          * @param {Object} old The item being replaced.
12766          * @param {Object} new The new item.
12767          */
12768         "replace" : true,
12769         /**
12770          * @event remove
12771          * Fires when an item is removed from the collection.
12772          * @param {Object} o The item being removed.
12773          * @param {String} key (optional) The key associated with the removed item.
12774          */
12775         "remove" : true,
12776         "sort" : true
12777     });
12778     this.allowFunctions = allowFunctions === true;
12779     if(keyFn){
12780         this.getKey = keyFn;
12781     }
12782     Roo.util.MixedCollection.superclass.constructor.call(this);
12783 };
12784
12785 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12786     allowFunctions : false,
12787     
12788 /**
12789  * Adds an item to the collection.
12790  * @param {String} key The key to associate with the item
12791  * @param {Object} o The item to add.
12792  * @return {Object} The item added.
12793  */
12794     add : function(key, o){
12795         if(arguments.length == 1){
12796             o = arguments[0];
12797             key = this.getKey(o);
12798         }
12799         if(typeof key == "undefined" || key === null){
12800             this.length++;
12801             this.items.push(o);
12802             this.keys.push(null);
12803         }else{
12804             var old = this.map[key];
12805             if(old){
12806                 return this.replace(key, o);
12807             }
12808             this.length++;
12809             this.items.push(o);
12810             this.map[key] = o;
12811             this.keys.push(key);
12812         }
12813         this.fireEvent("add", this.length-1, o, key);
12814         return o;
12815     },
12816        
12817 /**
12818   * MixedCollection has a generic way to fetch keys if you implement getKey.
12819 <pre><code>
12820 // normal way
12821 var mc = new Roo.util.MixedCollection();
12822 mc.add(someEl.dom.id, someEl);
12823 mc.add(otherEl.dom.id, otherEl);
12824 //and so on
12825
12826 // using getKey
12827 var mc = new Roo.util.MixedCollection();
12828 mc.getKey = function(el){
12829    return el.dom.id;
12830 };
12831 mc.add(someEl);
12832 mc.add(otherEl);
12833
12834 // or via the constructor
12835 var mc = new Roo.util.MixedCollection(false, function(el){
12836    return el.dom.id;
12837 });
12838 mc.add(someEl);
12839 mc.add(otherEl);
12840 </code></pre>
12841  * @param o {Object} The item for which to find the key.
12842  * @return {Object} The key for the passed item.
12843  */
12844     getKey : function(o){
12845          return o.id; 
12846     },
12847    
12848 /**
12849  * Replaces an item in the collection.
12850  * @param {String} key The key associated with the item to replace, or the item to replace.
12851  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12852  * @return {Object}  The new item.
12853  */
12854     replace : function(key, o){
12855         if(arguments.length == 1){
12856             o = arguments[0];
12857             key = this.getKey(o);
12858         }
12859         var old = this.item(key);
12860         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12861              return this.add(key, o);
12862         }
12863         var index = this.indexOfKey(key);
12864         this.items[index] = o;
12865         this.map[key] = o;
12866         this.fireEvent("replace", key, old, o);
12867         return o;
12868     },
12869    
12870 /**
12871  * Adds all elements of an Array or an Object to the collection.
12872  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12873  * an Array of values, each of which are added to the collection.
12874  */
12875     addAll : function(objs){
12876         if(arguments.length > 1 || objs instanceof Array){
12877             var args = arguments.length > 1 ? arguments : objs;
12878             for(var i = 0, len = args.length; i < len; i++){
12879                 this.add(args[i]);
12880             }
12881         }else{
12882             for(var key in objs){
12883                 if(this.allowFunctions || typeof objs[key] != "function"){
12884                     this.add(key, objs[key]);
12885                 }
12886             }
12887         }
12888     },
12889    
12890 /**
12891  * Executes the specified function once for every item in the collection, passing each
12892  * item as the first and only parameter. returning false from the function will stop the iteration.
12893  * @param {Function} fn The function to execute for each item.
12894  * @param {Object} scope (optional) The scope in which to execute the function.
12895  */
12896     each : function(fn, scope){
12897         var items = [].concat(this.items); // each safe for removal
12898         for(var i = 0, len = items.length; i < len; i++){
12899             if(fn.call(scope || items[i], items[i], i, len) === false){
12900                 break;
12901             }
12902         }
12903     },
12904    
12905 /**
12906  * Executes the specified function once for every key in the collection, passing each
12907  * key, and its associated item as the first two parameters.
12908  * @param {Function} fn The function to execute for each item.
12909  * @param {Object} scope (optional) The scope in which to execute the function.
12910  */
12911     eachKey : function(fn, scope){
12912         for(var i = 0, len = this.keys.length; i < len; i++){
12913             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12914         }
12915     },
12916    
12917 /**
12918  * Returns the first item in the collection which elicits a true return value from the
12919  * passed selection function.
12920  * @param {Function} fn The selection function to execute for each item.
12921  * @param {Object} scope (optional) The scope in which to execute the function.
12922  * @return {Object} The first item in the collection which returned true from the selection function.
12923  */
12924     find : function(fn, scope){
12925         for(var i = 0, len = this.items.length; i < len; i++){
12926             if(fn.call(scope || window, this.items[i], this.keys[i])){
12927                 return this.items[i];
12928             }
12929         }
12930         return null;
12931     },
12932    
12933 /**
12934  * Inserts an item at the specified index in the collection.
12935  * @param {Number} index The index to insert the item at.
12936  * @param {String} key The key to associate with the new item, or the item itself.
12937  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12938  * @return {Object} The item inserted.
12939  */
12940     insert : function(index, key, o){
12941         if(arguments.length == 2){
12942             o = arguments[1];
12943             key = this.getKey(o);
12944         }
12945         if(index >= this.length){
12946             return this.add(key, o);
12947         }
12948         this.length++;
12949         this.items.splice(index, 0, o);
12950         if(typeof key != "undefined" && key != null){
12951             this.map[key] = o;
12952         }
12953         this.keys.splice(index, 0, key);
12954         this.fireEvent("add", index, o, key);
12955         return o;
12956     },
12957    
12958 /**
12959  * Removed an item from the collection.
12960  * @param {Object} o The item to remove.
12961  * @return {Object} The item removed.
12962  */
12963     remove : function(o){
12964         return this.removeAt(this.indexOf(o));
12965     },
12966    
12967 /**
12968  * Remove an item from a specified index in the collection.
12969  * @param {Number} index The index within the collection of the item to remove.
12970  */
12971     removeAt : function(index){
12972         if(index < this.length && index >= 0){
12973             this.length--;
12974             var o = this.items[index];
12975             this.items.splice(index, 1);
12976             var key = this.keys[index];
12977             if(typeof key != "undefined"){
12978                 delete this.map[key];
12979             }
12980             this.keys.splice(index, 1);
12981             this.fireEvent("remove", o, key);
12982         }
12983     },
12984    
12985 /**
12986  * Removed an item associated with the passed key fom the collection.
12987  * @param {String} key The key of the item to remove.
12988  */
12989     removeKey : function(key){
12990         return this.removeAt(this.indexOfKey(key));
12991     },
12992    
12993 /**
12994  * Returns the number of items in the collection.
12995  * @return {Number} the number of items in the collection.
12996  */
12997     getCount : function(){
12998         return this.length; 
12999     },
13000    
13001 /**
13002  * Returns index within the collection of the passed Object.
13003  * @param {Object} o The item to find the index of.
13004  * @return {Number} index of the item.
13005  */
13006     indexOf : function(o){
13007         if(!this.items.indexOf){
13008             for(var i = 0, len = this.items.length; i < len; i++){
13009                 if(this.items[i] == o) return i;
13010             }
13011             return -1;
13012         }else{
13013             return this.items.indexOf(o);
13014         }
13015     },
13016    
13017 /**
13018  * Returns index within the collection of the passed key.
13019  * @param {String} key The key to find the index of.
13020  * @return {Number} index of the key.
13021  */
13022     indexOfKey : function(key){
13023         if(!this.keys.indexOf){
13024             for(var i = 0, len = this.keys.length; i < len; i++){
13025                 if(this.keys[i] == key) return i;
13026             }
13027             return -1;
13028         }else{
13029             return this.keys.indexOf(key);
13030         }
13031     },
13032    
13033 /**
13034  * Returns the item associated with the passed key OR index. Key has priority over index.
13035  * @param {String/Number} key The key or index of the item.
13036  * @return {Object} The item associated with the passed key.
13037  */
13038     item : function(key){
13039         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13040         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13041     },
13042     
13043 /**
13044  * Returns the item at the specified index.
13045  * @param {Number} index The index of the item.
13046  * @return {Object}
13047  */
13048     itemAt : function(index){
13049         return this.items[index];
13050     },
13051     
13052 /**
13053  * Returns the item associated with the passed key.
13054  * @param {String/Number} key The key of the item.
13055  * @return {Object} The item associated with the passed key.
13056  */
13057     key : function(key){
13058         return this.map[key];
13059     },
13060    
13061 /**
13062  * Returns true if the collection contains the passed Object as an item.
13063  * @param {Object} o  The Object to look for in the collection.
13064  * @return {Boolean} True if the collection contains the Object as an item.
13065  */
13066     contains : function(o){
13067         return this.indexOf(o) != -1;
13068     },
13069    
13070 /**
13071  * Returns true if the collection contains the passed Object as a key.
13072  * @param {String} key The key to look for in the collection.
13073  * @return {Boolean} True if the collection contains the Object as a key.
13074  */
13075     containsKey : function(key){
13076         return typeof this.map[key] != "undefined";
13077     },
13078    
13079 /**
13080  * Removes all items from the collection.
13081  */
13082     clear : function(){
13083         this.length = 0;
13084         this.items = [];
13085         this.keys = [];
13086         this.map = {};
13087         this.fireEvent("clear");
13088     },
13089    
13090 /**
13091  * Returns the first item in the collection.
13092  * @return {Object} the first item in the collection..
13093  */
13094     first : function(){
13095         return this.items[0]; 
13096     },
13097    
13098 /**
13099  * Returns the last item in the collection.
13100  * @return {Object} the last item in the collection..
13101  */
13102     last : function(){
13103         return this.items[this.length-1];   
13104     },
13105     
13106     _sort : function(property, dir, fn){
13107         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13108         fn = fn || function(a, b){
13109             return a-b;
13110         };
13111         var c = [], k = this.keys, items = this.items;
13112         for(var i = 0, len = items.length; i < len; i++){
13113             c[c.length] = {key: k[i], value: items[i], index: i};
13114         }
13115         c.sort(function(a, b){
13116             var v = fn(a[property], b[property]) * dsc;
13117             if(v == 0){
13118                 v = (a.index < b.index ? -1 : 1);
13119             }
13120             return v;
13121         });
13122         for(var i = 0, len = c.length; i < len; i++){
13123             items[i] = c[i].value;
13124             k[i] = c[i].key;
13125         }
13126         this.fireEvent("sort", this);
13127     },
13128     
13129     /**
13130      * Sorts this collection with the passed comparison function
13131      * @param {String} direction (optional) "ASC" or "DESC"
13132      * @param {Function} fn (optional) comparison function
13133      */
13134     sort : function(dir, fn){
13135         this._sort("value", dir, fn);
13136     },
13137     
13138     /**
13139      * Sorts this collection by keys
13140      * @param {String} direction (optional) "ASC" or "DESC"
13141      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13142      */
13143     keySort : function(dir, fn){
13144         this._sort("key", dir, fn || function(a, b){
13145             return String(a).toUpperCase()-String(b).toUpperCase();
13146         });
13147     },
13148     
13149     /**
13150      * Returns a range of items in this collection
13151      * @param {Number} startIndex (optional) defaults to 0
13152      * @param {Number} endIndex (optional) default to the last item
13153      * @return {Array} An array of items
13154      */
13155     getRange : function(start, end){
13156         var items = this.items;
13157         if(items.length < 1){
13158             return [];
13159         }
13160         start = start || 0;
13161         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13162         var r = [];
13163         if(start <= end){
13164             for(var i = start; i <= end; i++) {
13165                     r[r.length] = items[i];
13166             }
13167         }else{
13168             for(var i = start; i >= end; i--) {
13169                     r[r.length] = items[i];
13170             }
13171         }
13172         return r;
13173     },
13174         
13175     /**
13176      * Filter the <i>objects</i> in this collection by a specific property. 
13177      * Returns a new collection that has been filtered.
13178      * @param {String} property A property on your objects
13179      * @param {String/RegExp} value Either string that the property values 
13180      * should start with or a RegExp to test against the property
13181      * @return {MixedCollection} The new filtered collection
13182      */
13183     filter : function(property, value){
13184         if(!value.exec){ // not a regex
13185             value = String(value);
13186             if(value.length == 0){
13187                 return this.clone();
13188             }
13189             value = new RegExp("^" + Roo.escapeRe(value), "i");
13190         }
13191         return this.filterBy(function(o){
13192             return o && value.test(o[property]);
13193         });
13194         },
13195     
13196     /**
13197      * Filter by a function. * Returns a new collection that has been filtered.
13198      * The passed function will be called with each 
13199      * object in the collection. If the function returns true, the value is included 
13200      * otherwise it is filtered.
13201      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13202      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13203      * @return {MixedCollection} The new filtered collection
13204      */
13205     filterBy : function(fn, scope){
13206         var r = new Roo.util.MixedCollection();
13207         r.getKey = this.getKey;
13208         var k = this.keys, it = this.items;
13209         for(var i = 0, len = it.length; i < len; i++){
13210             if(fn.call(scope||this, it[i], k[i])){
13211                                 r.add(k[i], it[i]);
13212                         }
13213         }
13214         return r;
13215     },
13216     
13217     /**
13218      * Creates a duplicate of this collection
13219      * @return {MixedCollection}
13220      */
13221     clone : function(){
13222         var r = new Roo.util.MixedCollection();
13223         var k = this.keys, it = this.items;
13224         for(var i = 0, len = it.length; i < len; i++){
13225             r.add(k[i], it[i]);
13226         }
13227         r.getKey = this.getKey;
13228         return r;
13229     }
13230 });
13231 /**
13232  * Returns the item associated with the passed key or index.
13233  * @method
13234  * @param {String/Number} key The key or index of the item.
13235  * @return {Object} The item associated with the passed key.
13236  */
13237 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13238  * Based on:
13239  * Ext JS Library 1.1.1
13240  * Copyright(c) 2006-2007, Ext JS, LLC.
13241  *
13242  * Originally Released Under LGPL - original licence link has changed is not relivant.
13243  *
13244  * Fork - LGPL
13245  * <script type="text/javascript">
13246  */
13247 /**
13248  * @class Roo.util.JSON
13249  * Modified version of Douglas Crockford"s json.js that doesn"t
13250  * mess with the Object prototype 
13251  * http://www.json.org/js.html
13252  * @singleton
13253  */
13254 Roo.util.JSON = new (function(){
13255     var useHasOwn = {}.hasOwnProperty ? true : false;
13256     
13257     // crashes Safari in some instances
13258     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13259     
13260     var pad = function(n) {
13261         return n < 10 ? "0" + n : n;
13262     };
13263     
13264     var m = {
13265         "\b": '\\b',
13266         "\t": '\\t',
13267         "\n": '\\n',
13268         "\f": '\\f',
13269         "\r": '\\r',
13270         '"' : '\\"',
13271         "\\": '\\\\'
13272     };
13273
13274     var encodeString = function(s){
13275         if (/["\\\x00-\x1f]/.test(s)) {
13276             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13277                 var c = m[b];
13278                 if(c){
13279                     return c;
13280                 }
13281                 c = b.charCodeAt();
13282                 return "\\u00" +
13283                     Math.floor(c / 16).toString(16) +
13284                     (c % 16).toString(16);
13285             }) + '"';
13286         }
13287         return '"' + s + '"';
13288     };
13289     
13290     var encodeArray = function(o){
13291         var a = ["["], b, i, l = o.length, v;
13292             for (i = 0; i < l; i += 1) {
13293                 v = o[i];
13294                 switch (typeof v) {
13295                     case "undefined":
13296                     case "function":
13297                     case "unknown":
13298                         break;
13299                     default:
13300                         if (b) {
13301                             a.push(',');
13302                         }
13303                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13304                         b = true;
13305                 }
13306             }
13307             a.push("]");
13308             return a.join("");
13309     };
13310     
13311     var encodeDate = function(o){
13312         return '"' + o.getFullYear() + "-" +
13313                 pad(o.getMonth() + 1) + "-" +
13314                 pad(o.getDate()) + "T" +
13315                 pad(o.getHours()) + ":" +
13316                 pad(o.getMinutes()) + ":" +
13317                 pad(o.getSeconds()) + '"';
13318     };
13319     
13320     /**
13321      * Encodes an Object, Array or other value
13322      * @param {Mixed} o The variable to encode
13323      * @return {String} The JSON string
13324      */
13325     this.encode = function(o)
13326     {
13327         // should this be extended to fully wrap stringify..
13328         
13329         if(typeof o == "undefined" || o === null){
13330             return "null";
13331         }else if(o instanceof Array){
13332             return encodeArray(o);
13333         }else if(o instanceof Date){
13334             return encodeDate(o);
13335         }else if(typeof o == "string"){
13336             return encodeString(o);
13337         }else if(typeof o == "number"){
13338             return isFinite(o) ? String(o) : "null";
13339         }else if(typeof o == "boolean"){
13340             return String(o);
13341         }else {
13342             var a = ["{"], b, i, v;
13343             for (i in o) {
13344                 if(!useHasOwn || o.hasOwnProperty(i)) {
13345                     v = o[i];
13346                     switch (typeof v) {
13347                     case "undefined":
13348                     case "function":
13349                     case "unknown":
13350                         break;
13351                     default:
13352                         if(b){
13353                             a.push(',');
13354                         }
13355                         a.push(this.encode(i), ":",
13356                                 v === null ? "null" : this.encode(v));
13357                         b = true;
13358                     }
13359                 }
13360             }
13361             a.push("}");
13362             return a.join("");
13363         }
13364     };
13365     
13366     /**
13367      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13368      * @param {String} json The JSON string
13369      * @return {Object} The resulting object
13370      */
13371     this.decode = function(json){
13372         
13373         return  /** eval:var:json */ eval("(" + json + ')');
13374     };
13375 })();
13376 /** 
13377  * Shorthand for {@link Roo.util.JSON#encode}
13378  * @member Roo encode 
13379  * @method */
13380 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13381 /** 
13382  * Shorthand for {@link Roo.util.JSON#decode}
13383  * @member Roo decode 
13384  * @method */
13385 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13386 /*
13387  * Based on:
13388  * Ext JS Library 1.1.1
13389  * Copyright(c) 2006-2007, Ext JS, LLC.
13390  *
13391  * Originally Released Under LGPL - original licence link has changed is not relivant.
13392  *
13393  * Fork - LGPL
13394  * <script type="text/javascript">
13395  */
13396  
13397 /**
13398  * @class Roo.util.Format
13399  * Reusable data formatting functions
13400  * @singleton
13401  */
13402 Roo.util.Format = function(){
13403     var trimRe = /^\s+|\s+$/g;
13404     return {
13405         /**
13406          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13407          * @param {String} value The string to truncate
13408          * @param {Number} length The maximum length to allow before truncating
13409          * @return {String} The converted text
13410          */
13411         ellipsis : function(value, len){
13412             if(value && value.length > len){
13413                 return value.substr(0, len-3)+"...";
13414             }
13415             return value;
13416         },
13417
13418         /**
13419          * Checks a reference and converts it to empty string if it is undefined
13420          * @param {Mixed} value Reference to check
13421          * @return {Mixed} Empty string if converted, otherwise the original value
13422          */
13423         undef : function(value){
13424             return typeof value != "undefined" ? value : "";
13425         },
13426
13427         /**
13428          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13429          * @param {String} value The string to encode
13430          * @return {String} The encoded text
13431          */
13432         htmlEncode : function(value){
13433             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13434         },
13435
13436         /**
13437          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13438          * @param {String} value The string to decode
13439          * @return {String} The decoded text
13440          */
13441         htmlDecode : function(value){
13442             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13443         },
13444
13445         /**
13446          * Trims any whitespace from either side of a string
13447          * @param {String} value The text to trim
13448          * @return {String} The trimmed text
13449          */
13450         trim : function(value){
13451             return String(value).replace(trimRe, "");
13452         },
13453
13454         /**
13455          * Returns a substring from within an original string
13456          * @param {String} value The original text
13457          * @param {Number} start The start index of the substring
13458          * @param {Number} length The length of the substring
13459          * @return {String} The substring
13460          */
13461         substr : function(value, start, length){
13462             return String(value).substr(start, length);
13463         },
13464
13465         /**
13466          * Converts a string to all lower case letters
13467          * @param {String} value The text to convert
13468          * @return {String} The converted text
13469          */
13470         lowercase : function(value){
13471             return String(value).toLowerCase();
13472         },
13473
13474         /**
13475          * Converts a string to all upper case letters
13476          * @param {String} value The text to convert
13477          * @return {String} The converted text
13478          */
13479         uppercase : function(value){
13480             return String(value).toUpperCase();
13481         },
13482
13483         /**
13484          * Converts the first character only of a string to upper case
13485          * @param {String} value The text to convert
13486          * @return {String} The converted text
13487          */
13488         capitalize : function(value){
13489             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13490         },
13491
13492         // private
13493         call : function(value, fn){
13494             if(arguments.length > 2){
13495                 var args = Array.prototype.slice.call(arguments, 2);
13496                 args.unshift(value);
13497                  
13498                 return /** eval:var:value */  eval(fn).apply(window, args);
13499             }else{
13500                 /** eval:var:value */
13501                 return /** eval:var:value */ eval(fn).call(window, value);
13502             }
13503         },
13504
13505        
13506         /**
13507          * safer version of Math.toFixed..??/
13508          * @param {Number/String} value The numeric value to format
13509          * @param {Number/String} value Decimal places 
13510          * @return {String} The formatted currency string
13511          */
13512         toFixed : function(v, n)
13513         {
13514             // why not use to fixed - precision is buggered???
13515             if (!n) {
13516                 return Math.round(v-0);
13517             }
13518             var fact = Math.pow(10,n+1);
13519             v = (Math.round((v-0)*fact))/fact;
13520             var z = (''+fact).substring(2);
13521             if (v == Math.floor(v)) {
13522                 return Math.floor(v) + '.' + z;
13523             }
13524             
13525             // now just padd decimals..
13526             var ps = String(v).split('.');
13527             var fd = (ps[1] + z);
13528             var r = fd.substring(0,n); 
13529             var rm = fd.substring(n); 
13530             if (rm < 5) {
13531                 return ps[0] + '.' + r;
13532             }
13533             r*=1; // turn it into a number;
13534             r++;
13535             if (String(r).length != n) {
13536                 ps[0]*=1;
13537                 ps[0]++;
13538                 r = String(r).substring(1); // chop the end off.
13539             }
13540             
13541             return ps[0] + '.' + r;
13542              
13543         },
13544         
13545         /**
13546          * Format a number as US currency
13547          * @param {Number/String} value The numeric value to format
13548          * @return {String} The formatted currency string
13549          */
13550         usMoney : function(v){
13551             return '$' + Roo.util.Format.number(v);
13552         },
13553         
13554         /**
13555          * Format a number
13556          * eventually this should probably emulate php's number_format
13557          * @param {Number/String} value The numeric value to format
13558          * @param {Number} decimals number of decimal places
13559          * @return {String} The formatted currency string
13560          */
13561         number : function(v,decimals)
13562         {
13563             // multiply and round.
13564             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13565             var mul = Math.pow(10, decimals);
13566             var zero = String(mul).substring(1);
13567             v = (Math.round((v-0)*mul))/mul;
13568             
13569             // if it's '0' number.. then
13570             
13571             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13572             v = String(v);
13573             var ps = v.split('.');
13574             var whole = ps[0];
13575             
13576             
13577             var r = /(\d+)(\d{3})/;
13578             // add comma's
13579             while (r.test(whole)) {
13580                 whole = whole.replace(r, '$1' + ',' + '$2');
13581             }
13582             
13583             
13584             var sub = ps[1] ?
13585                     // has decimals..
13586                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13587                     // does not have decimals
13588                     (decimals ? ('.' + zero) : '');
13589             
13590             
13591             return whole + sub ;
13592         },
13593         
13594         /**
13595          * Parse a value into a formatted date using the specified format pattern.
13596          * @param {Mixed} value The value to format
13597          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13598          * @return {String} The formatted date string
13599          */
13600         date : function(v, format){
13601             if(!v){
13602                 return "";
13603             }
13604             if(!(v instanceof Date)){
13605                 v = new Date(Date.parse(v));
13606             }
13607             return v.dateFormat(format || "m/d/Y");
13608         },
13609
13610         /**
13611          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13612          * @param {String} format Any valid date format string
13613          * @return {Function} The date formatting function
13614          */
13615         dateRenderer : function(format){
13616             return function(v){
13617                 return Roo.util.Format.date(v, format);  
13618             };
13619         },
13620
13621         // private
13622         stripTagsRE : /<\/?[^>]+>/gi,
13623         
13624         /**
13625          * Strips all HTML tags
13626          * @param {Mixed} value The text from which to strip tags
13627          * @return {String} The stripped text
13628          */
13629         stripTags : function(v){
13630             return !v ? v : String(v).replace(this.stripTagsRE, "");
13631         }
13632     };
13633 }();/*
13634  * Based on:
13635  * Ext JS Library 1.1.1
13636  * Copyright(c) 2006-2007, Ext JS, LLC.
13637  *
13638  * Originally Released Under LGPL - original licence link has changed is not relivant.
13639  *
13640  * Fork - LGPL
13641  * <script type="text/javascript">
13642  */
13643
13644
13645  
13646
13647 /**
13648  * @class Roo.MasterTemplate
13649  * @extends Roo.Template
13650  * Provides a template that can have child templates. The syntax is:
13651 <pre><code>
13652 var t = new Roo.MasterTemplate(
13653         '&lt;select name="{name}"&gt;',
13654                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13655         '&lt;/select&gt;'
13656 );
13657 t.add('options', {value: 'foo', text: 'bar'});
13658 // or you can add multiple child elements in one shot
13659 t.addAll('options', [
13660     {value: 'foo', text: 'bar'},
13661     {value: 'foo2', text: 'bar2'},
13662     {value: 'foo3', text: 'bar3'}
13663 ]);
13664 // then append, applying the master template values
13665 t.append('my-form', {name: 'my-select'});
13666 </code></pre>
13667 * A name attribute for the child template is not required if you have only one child
13668 * template or you want to refer to them by index.
13669  */
13670 Roo.MasterTemplate = function(){
13671     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13672     this.originalHtml = this.html;
13673     var st = {};
13674     var m, re = this.subTemplateRe;
13675     re.lastIndex = 0;
13676     var subIndex = 0;
13677     while(m = re.exec(this.html)){
13678         var name = m[1], content = m[2];
13679         st[subIndex] = {
13680             name: name,
13681             index: subIndex,
13682             buffer: [],
13683             tpl : new Roo.Template(content)
13684         };
13685         if(name){
13686             st[name] = st[subIndex];
13687         }
13688         st[subIndex].tpl.compile();
13689         st[subIndex].tpl.call = this.call.createDelegate(this);
13690         subIndex++;
13691     }
13692     this.subCount = subIndex;
13693     this.subs = st;
13694 };
13695 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13696     /**
13697     * The regular expression used to match sub templates
13698     * @type RegExp
13699     * @property
13700     */
13701     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13702
13703     /**
13704      * Applies the passed values to a child template.
13705      * @param {String/Number} name (optional) The name or index of the child template
13706      * @param {Array/Object} values The values to be applied to the template
13707      * @return {MasterTemplate} this
13708      */
13709      add : function(name, values){
13710         if(arguments.length == 1){
13711             values = arguments[0];
13712             name = 0;
13713         }
13714         var s = this.subs[name];
13715         s.buffer[s.buffer.length] = s.tpl.apply(values);
13716         return this;
13717     },
13718
13719     /**
13720      * Applies all the passed values to a child template.
13721      * @param {String/Number} name (optional) The name or index of the child template
13722      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13723      * @param {Boolean} reset (optional) True to reset the template first
13724      * @return {MasterTemplate} this
13725      */
13726     fill : function(name, values, reset){
13727         var a = arguments;
13728         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13729             values = a[0];
13730             name = 0;
13731             reset = a[1];
13732         }
13733         if(reset){
13734             this.reset();
13735         }
13736         for(var i = 0, len = values.length; i < len; i++){
13737             this.add(name, values[i]);
13738         }
13739         return this;
13740     },
13741
13742     /**
13743      * Resets the template for reuse
13744      * @return {MasterTemplate} this
13745      */
13746      reset : function(){
13747         var s = this.subs;
13748         for(var i = 0; i < this.subCount; i++){
13749             s[i].buffer = [];
13750         }
13751         return this;
13752     },
13753
13754     applyTemplate : function(values){
13755         var s = this.subs;
13756         var replaceIndex = -1;
13757         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13758             return s[++replaceIndex].buffer.join("");
13759         });
13760         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13761     },
13762
13763     apply : function(){
13764         return this.applyTemplate.apply(this, arguments);
13765     },
13766
13767     compile : function(){return this;}
13768 });
13769
13770 /**
13771  * Alias for fill().
13772  * @method
13773  */
13774 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13775  /**
13776  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13777  * var tpl = Roo.MasterTemplate.from('element-id');
13778  * @param {String/HTMLElement} el
13779  * @param {Object} config
13780  * @static
13781  */
13782 Roo.MasterTemplate.from = function(el, config){
13783     el = Roo.getDom(el);
13784     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13785 };/*
13786  * Based on:
13787  * Ext JS Library 1.1.1
13788  * Copyright(c) 2006-2007, Ext JS, LLC.
13789  *
13790  * Originally Released Under LGPL - original licence link has changed is not relivant.
13791  *
13792  * Fork - LGPL
13793  * <script type="text/javascript">
13794  */
13795
13796  
13797 /**
13798  * @class Roo.util.CSS
13799  * Utility class for manipulating CSS rules
13800  * @singleton
13801  */
13802 Roo.util.CSS = function(){
13803         var rules = null;
13804         var doc = document;
13805
13806     var camelRe = /(-[a-z])/gi;
13807     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13808
13809    return {
13810    /**
13811     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13812     * tag and appended to the HEAD of the document.
13813     * @param {String|Object} cssText The text containing the css rules
13814     * @param {String} id An id to add to the stylesheet for later removal
13815     * @return {StyleSheet}
13816     */
13817     createStyleSheet : function(cssText, id){
13818         var ss;
13819         var head = doc.getElementsByTagName("head")[0];
13820         var nrules = doc.createElement("style");
13821         nrules.setAttribute("type", "text/css");
13822         if(id){
13823             nrules.setAttribute("id", id);
13824         }
13825         if (typeof(cssText) != 'string') {
13826             // support object maps..
13827             // not sure if this a good idea.. 
13828             // perhaps it should be merged with the general css handling
13829             // and handle js style props.
13830             var cssTextNew = [];
13831             for(var n in cssText) {
13832                 var citems = [];
13833                 for(var k in cssText[n]) {
13834                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13835                 }
13836                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13837                 
13838             }
13839             cssText = cssTextNew.join("\n");
13840             
13841         }
13842        
13843        
13844        if(Roo.isIE){
13845            head.appendChild(nrules);
13846            ss = nrules.styleSheet;
13847            ss.cssText = cssText;
13848        }else{
13849            try{
13850                 nrules.appendChild(doc.createTextNode(cssText));
13851            }catch(e){
13852                nrules.cssText = cssText; 
13853            }
13854            head.appendChild(nrules);
13855            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13856        }
13857        this.cacheStyleSheet(ss);
13858        return ss;
13859    },
13860
13861    /**
13862     * Removes a style or link tag by id
13863     * @param {String} id The id of the tag
13864     */
13865    removeStyleSheet : function(id){
13866        var existing = doc.getElementById(id);
13867        if(existing){
13868            existing.parentNode.removeChild(existing);
13869        }
13870    },
13871
13872    /**
13873     * Dynamically swaps an existing stylesheet reference for a new one
13874     * @param {String} id The id of an existing link tag to remove
13875     * @param {String} url The href of the new stylesheet to include
13876     */
13877    swapStyleSheet : function(id, url){
13878        this.removeStyleSheet(id);
13879        var ss = doc.createElement("link");
13880        ss.setAttribute("rel", "stylesheet");
13881        ss.setAttribute("type", "text/css");
13882        ss.setAttribute("id", id);
13883        ss.setAttribute("href", url);
13884        doc.getElementsByTagName("head")[0].appendChild(ss);
13885    },
13886    
13887    /**
13888     * Refresh the rule cache if you have dynamically added stylesheets
13889     * @return {Object} An object (hash) of rules indexed by selector
13890     */
13891    refreshCache : function(){
13892        return this.getRules(true);
13893    },
13894
13895    // private
13896    cacheStyleSheet : function(stylesheet){
13897        if(!rules){
13898            rules = {};
13899        }
13900        try{// try catch for cross domain access issue
13901            var ssRules = stylesheet.cssRules || stylesheet.rules;
13902            for(var j = ssRules.length-1; j >= 0; --j){
13903                rules[ssRules[j].selectorText] = ssRules[j];
13904            }
13905        }catch(e){}
13906    },
13907    
13908    /**
13909     * Gets all css rules for the document
13910     * @param {Boolean} refreshCache true to refresh the internal cache
13911     * @return {Object} An object (hash) of rules indexed by selector
13912     */
13913    getRules : function(refreshCache){
13914                 if(rules == null || refreshCache){
13915                         rules = {};
13916                         var ds = doc.styleSheets;
13917                         for(var i =0, len = ds.length; i < len; i++){
13918                             try{
13919                         this.cacheStyleSheet(ds[i]);
13920                     }catch(e){} 
13921                 }
13922                 }
13923                 return rules;
13924         },
13925         
13926         /**
13927     * Gets an an individual CSS rule by selector(s)
13928     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13929     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13930     * @return {CSSRule} The CSS rule or null if one is not found
13931     */
13932    getRule : function(selector, refreshCache){
13933                 var rs = this.getRules(refreshCache);
13934                 if(!(selector instanceof Array)){
13935                     return rs[selector];
13936                 }
13937                 for(var i = 0; i < selector.length; i++){
13938                         if(rs[selector[i]]){
13939                                 return rs[selector[i]];
13940                         }
13941                 }
13942                 return null;
13943         },
13944         
13945         
13946         /**
13947     * Updates a rule property
13948     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13949     * @param {String} property The css property
13950     * @param {String} value The new value for the property
13951     * @return {Boolean} true If a rule was found and updated
13952     */
13953    updateRule : function(selector, property, value){
13954                 if(!(selector instanceof Array)){
13955                         var rule = this.getRule(selector);
13956                         if(rule){
13957                                 rule.style[property.replace(camelRe, camelFn)] = value;
13958                                 return true;
13959                         }
13960                 }else{
13961                         for(var i = 0; i < selector.length; i++){
13962                                 if(this.updateRule(selector[i], property, value)){
13963                                         return true;
13964                                 }
13965                         }
13966                 }
13967                 return false;
13968         }
13969    };   
13970 }();/*
13971  * Based on:
13972  * Ext JS Library 1.1.1
13973  * Copyright(c) 2006-2007, Ext JS, LLC.
13974  *
13975  * Originally Released Under LGPL - original licence link has changed is not relivant.
13976  *
13977  * Fork - LGPL
13978  * <script type="text/javascript">
13979  */
13980
13981  
13982
13983 /**
13984  * @class Roo.util.ClickRepeater
13985  * @extends Roo.util.Observable
13986  * 
13987  * A wrapper class which can be applied to any element. Fires a "click" event while the
13988  * mouse is pressed. The interval between firings may be specified in the config but
13989  * defaults to 10 milliseconds.
13990  * 
13991  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13992  * 
13993  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13994  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13995  * Similar to an autorepeat key delay.
13996  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13997  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13998  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13999  *           "interval" and "delay" are ignored. "immediate" is honored.
14000  * @cfg {Boolean} preventDefault True to prevent the default click event
14001  * @cfg {Boolean} stopDefault True to stop the default click event
14002  * 
14003  * @history
14004  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14005  *     2007-02-02 jvs Renamed to ClickRepeater
14006  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14007  *
14008  *  @constructor
14009  * @param {String/HTMLElement/Element} el The element to listen on
14010  * @param {Object} config
14011  **/
14012 Roo.util.ClickRepeater = function(el, config)
14013 {
14014     this.el = Roo.get(el);
14015     this.el.unselectable();
14016
14017     Roo.apply(this, config);
14018
14019     this.addEvents({
14020     /**
14021      * @event mousedown
14022      * Fires when the mouse button is depressed.
14023      * @param {Roo.util.ClickRepeater} this
14024      */
14025         "mousedown" : true,
14026     /**
14027      * @event click
14028      * Fires on a specified interval during the time the element is pressed.
14029      * @param {Roo.util.ClickRepeater} this
14030      */
14031         "click" : true,
14032     /**
14033      * @event mouseup
14034      * Fires when the mouse key is released.
14035      * @param {Roo.util.ClickRepeater} this
14036      */
14037         "mouseup" : true
14038     });
14039
14040     this.el.on("mousedown", this.handleMouseDown, this);
14041     if(this.preventDefault || this.stopDefault){
14042         this.el.on("click", function(e){
14043             if(this.preventDefault){
14044                 e.preventDefault();
14045             }
14046             if(this.stopDefault){
14047                 e.stopEvent();
14048             }
14049         }, this);
14050     }
14051
14052     // allow inline handler
14053     if(this.handler){
14054         this.on("click", this.handler,  this.scope || this);
14055     }
14056
14057     Roo.util.ClickRepeater.superclass.constructor.call(this);
14058 };
14059
14060 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14061     interval : 20,
14062     delay: 250,
14063     preventDefault : true,
14064     stopDefault : false,
14065     timer : 0,
14066
14067     // private
14068     handleMouseDown : function(){
14069         clearTimeout(this.timer);
14070         this.el.blur();
14071         if(this.pressClass){
14072             this.el.addClass(this.pressClass);
14073         }
14074         this.mousedownTime = new Date();
14075
14076         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14077         this.el.on("mouseout", this.handleMouseOut, this);
14078
14079         this.fireEvent("mousedown", this);
14080         this.fireEvent("click", this);
14081         
14082         this.timer = this.click.defer(this.delay || this.interval, this);
14083     },
14084
14085     // private
14086     click : function(){
14087         this.fireEvent("click", this);
14088         this.timer = this.click.defer(this.getInterval(), this);
14089     },
14090
14091     // private
14092     getInterval: function(){
14093         if(!this.accelerate){
14094             return this.interval;
14095         }
14096         var pressTime = this.mousedownTime.getElapsed();
14097         if(pressTime < 500){
14098             return 400;
14099         }else if(pressTime < 1700){
14100             return 320;
14101         }else if(pressTime < 2600){
14102             return 250;
14103         }else if(pressTime < 3500){
14104             return 180;
14105         }else if(pressTime < 4400){
14106             return 140;
14107         }else if(pressTime < 5300){
14108             return 80;
14109         }else if(pressTime < 6200){
14110             return 50;
14111         }else{
14112             return 10;
14113         }
14114     },
14115
14116     // private
14117     handleMouseOut : function(){
14118         clearTimeout(this.timer);
14119         if(this.pressClass){
14120             this.el.removeClass(this.pressClass);
14121         }
14122         this.el.on("mouseover", this.handleMouseReturn, this);
14123     },
14124
14125     // private
14126     handleMouseReturn : function(){
14127         this.el.un("mouseover", this.handleMouseReturn);
14128         if(this.pressClass){
14129             this.el.addClass(this.pressClass);
14130         }
14131         this.click();
14132     },
14133
14134     // private
14135     handleMouseUp : function(){
14136         clearTimeout(this.timer);
14137         this.el.un("mouseover", this.handleMouseReturn);
14138         this.el.un("mouseout", this.handleMouseOut);
14139         Roo.get(document).un("mouseup", this.handleMouseUp);
14140         this.el.removeClass(this.pressClass);
14141         this.fireEvent("mouseup", this);
14142     }
14143 });/*
14144  * Based on:
14145  * Ext JS Library 1.1.1
14146  * Copyright(c) 2006-2007, Ext JS, LLC.
14147  *
14148  * Originally Released Under LGPL - original licence link has changed is not relivant.
14149  *
14150  * Fork - LGPL
14151  * <script type="text/javascript">
14152  */
14153
14154  
14155 /**
14156  * @class Roo.KeyNav
14157  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14158  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14159  * way to implement custom navigation schemes for any UI component.</p>
14160  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14161  * pageUp, pageDown, del, home, end.  Usage:</p>
14162  <pre><code>
14163 var nav = new Roo.KeyNav("my-element", {
14164     "left" : function(e){
14165         this.moveLeft(e.ctrlKey);
14166     },
14167     "right" : function(e){
14168         this.moveRight(e.ctrlKey);
14169     },
14170     "enter" : function(e){
14171         this.save();
14172     },
14173     scope : this
14174 });
14175 </code></pre>
14176  * @constructor
14177  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14178  * @param {Object} config The config
14179  */
14180 Roo.KeyNav = function(el, config){
14181     this.el = Roo.get(el);
14182     Roo.apply(this, config);
14183     if(!this.disabled){
14184         this.disabled = true;
14185         this.enable();
14186     }
14187 };
14188
14189 Roo.KeyNav.prototype = {
14190     /**
14191      * @cfg {Boolean} disabled
14192      * True to disable this KeyNav instance (defaults to false)
14193      */
14194     disabled : false,
14195     /**
14196      * @cfg {String} defaultEventAction
14197      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14198      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14199      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14200      */
14201     defaultEventAction: "stopEvent",
14202     /**
14203      * @cfg {Boolean} forceKeyDown
14204      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14205      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14206      * handle keydown instead of keypress.
14207      */
14208     forceKeyDown : false,
14209
14210     // private
14211     prepareEvent : function(e){
14212         var k = e.getKey();
14213         var h = this.keyToHandler[k];
14214         //if(h && this[h]){
14215         //    e.stopPropagation();
14216         //}
14217         if(Roo.isSafari && h && k >= 37 && k <= 40){
14218             e.stopEvent();
14219         }
14220     },
14221
14222     // private
14223     relay : function(e){
14224         var k = e.getKey();
14225         var h = this.keyToHandler[k];
14226         if(h && this[h]){
14227             if(this.doRelay(e, this[h], h) !== true){
14228                 e[this.defaultEventAction]();
14229             }
14230         }
14231     },
14232
14233     // private
14234     doRelay : function(e, h, hname){
14235         return h.call(this.scope || this, e);
14236     },
14237
14238     // possible handlers
14239     enter : false,
14240     left : false,
14241     right : false,
14242     up : false,
14243     down : false,
14244     tab : false,
14245     esc : false,
14246     pageUp : false,
14247     pageDown : false,
14248     del : false,
14249     home : false,
14250     end : false,
14251
14252     // quick lookup hash
14253     keyToHandler : {
14254         37 : "left",
14255         39 : "right",
14256         38 : "up",
14257         40 : "down",
14258         33 : "pageUp",
14259         34 : "pageDown",
14260         46 : "del",
14261         36 : "home",
14262         35 : "end",
14263         13 : "enter",
14264         27 : "esc",
14265         9  : "tab"
14266     },
14267
14268         /**
14269          * Enable this KeyNav
14270          */
14271         enable: function(){
14272                 if(this.disabled){
14273             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14274             // the EventObject will normalize Safari automatically
14275             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14276                 this.el.on("keydown", this.relay,  this);
14277             }else{
14278                 this.el.on("keydown", this.prepareEvent,  this);
14279                 this.el.on("keypress", this.relay,  this);
14280             }
14281                     this.disabled = false;
14282                 }
14283         },
14284
14285         /**
14286          * Disable this KeyNav
14287          */
14288         disable: function(){
14289                 if(!this.disabled){
14290                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14291                 this.el.un("keydown", this.relay);
14292             }else{
14293                 this.el.un("keydown", this.prepareEvent);
14294                 this.el.un("keypress", this.relay);
14295             }
14296                     this.disabled = true;
14297                 }
14298         }
14299 };/*
14300  * Based on:
14301  * Ext JS Library 1.1.1
14302  * Copyright(c) 2006-2007, Ext JS, LLC.
14303  *
14304  * Originally Released Under LGPL - original licence link has changed is not relivant.
14305  *
14306  * Fork - LGPL
14307  * <script type="text/javascript">
14308  */
14309
14310  
14311 /**
14312  * @class Roo.KeyMap
14313  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14314  * The constructor accepts the same config object as defined by {@link #addBinding}.
14315  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14316  * combination it will call the function with this signature (if the match is a multi-key
14317  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14318  * A KeyMap can also handle a string representation of keys.<br />
14319  * Usage:
14320  <pre><code>
14321 // map one key by key code
14322 var map = new Roo.KeyMap("my-element", {
14323     key: 13, // or Roo.EventObject.ENTER
14324     fn: myHandler,
14325     scope: myObject
14326 });
14327
14328 // map multiple keys to one action by string
14329 var map = new Roo.KeyMap("my-element", {
14330     key: "a\r\n\t",
14331     fn: myHandler,
14332     scope: myObject
14333 });
14334
14335 // map multiple keys to multiple actions by strings and array of codes
14336 var map = new Roo.KeyMap("my-element", [
14337     {
14338         key: [10,13],
14339         fn: function(){ alert("Return was pressed"); }
14340     }, {
14341         key: "abc",
14342         fn: function(){ alert('a, b or c was pressed'); }
14343     }, {
14344         key: "\t",
14345         ctrl:true,
14346         shift:true,
14347         fn: function(){ alert('Control + shift + tab was pressed.'); }
14348     }
14349 ]);
14350 </code></pre>
14351  * <b>Note: A KeyMap starts enabled</b>
14352  * @constructor
14353  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14354  * @param {Object} config The config (see {@link #addBinding})
14355  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14356  */
14357 Roo.KeyMap = function(el, config, eventName){
14358     this.el  = Roo.get(el);
14359     this.eventName = eventName || "keydown";
14360     this.bindings = [];
14361     if(config){
14362         this.addBinding(config);
14363     }
14364     this.enable();
14365 };
14366
14367 Roo.KeyMap.prototype = {
14368     /**
14369      * True to stop the event from bubbling and prevent the default browser action if the
14370      * key was handled by the KeyMap (defaults to false)
14371      * @type Boolean
14372      */
14373     stopEvent : false,
14374
14375     /**
14376      * Add a new binding to this KeyMap. The following config object properties are supported:
14377      * <pre>
14378 Property    Type             Description
14379 ----------  ---------------  ----------------------------------------------------------------------
14380 key         String/Array     A single keycode or an array of keycodes to handle
14381 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14382 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14383 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14384 fn          Function         The function to call when KeyMap finds the expected key combination
14385 scope       Object           The scope of the callback function
14386 </pre>
14387      *
14388      * Usage:
14389      * <pre><code>
14390 // Create a KeyMap
14391 var map = new Roo.KeyMap(document, {
14392     key: Roo.EventObject.ENTER,
14393     fn: handleKey,
14394     scope: this
14395 });
14396
14397 //Add a new binding to the existing KeyMap later
14398 map.addBinding({
14399     key: 'abc',
14400     shift: true,
14401     fn: handleKey,
14402     scope: this
14403 });
14404 </code></pre>
14405      * @param {Object/Array} config A single KeyMap config or an array of configs
14406      */
14407         addBinding : function(config){
14408         if(config instanceof Array){
14409             for(var i = 0, len = config.length; i < len; i++){
14410                 this.addBinding(config[i]);
14411             }
14412             return;
14413         }
14414         var keyCode = config.key,
14415             shift = config.shift, 
14416             ctrl = config.ctrl, 
14417             alt = config.alt,
14418             fn = config.fn,
14419             scope = config.scope;
14420         if(typeof keyCode == "string"){
14421             var ks = [];
14422             var keyString = keyCode.toUpperCase();
14423             for(var j = 0, len = keyString.length; j < len; j++){
14424                 ks.push(keyString.charCodeAt(j));
14425             }
14426             keyCode = ks;
14427         }
14428         var keyArray = keyCode instanceof Array;
14429         var handler = function(e){
14430             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14431                 var k = e.getKey();
14432                 if(keyArray){
14433                     for(var i = 0, len = keyCode.length; i < len; i++){
14434                         if(keyCode[i] == k){
14435                           if(this.stopEvent){
14436                               e.stopEvent();
14437                           }
14438                           fn.call(scope || window, k, e);
14439                           return;
14440                         }
14441                     }
14442                 }else{
14443                     if(k == keyCode){
14444                         if(this.stopEvent){
14445                            e.stopEvent();
14446                         }
14447                         fn.call(scope || window, k, e);
14448                     }
14449                 }
14450             }
14451         };
14452         this.bindings.push(handler);  
14453         },
14454
14455     /**
14456      * Shorthand for adding a single key listener
14457      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14458      * following options:
14459      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14460      * @param {Function} fn The function to call
14461      * @param {Object} scope (optional) The scope of the function
14462      */
14463     on : function(key, fn, scope){
14464         var keyCode, shift, ctrl, alt;
14465         if(typeof key == "object" && !(key instanceof Array)){
14466             keyCode = key.key;
14467             shift = key.shift;
14468             ctrl = key.ctrl;
14469             alt = key.alt;
14470         }else{
14471             keyCode = key;
14472         }
14473         this.addBinding({
14474             key: keyCode,
14475             shift: shift,
14476             ctrl: ctrl,
14477             alt: alt,
14478             fn: fn,
14479             scope: scope
14480         })
14481     },
14482
14483     // private
14484     handleKeyDown : function(e){
14485             if(this.enabled){ //just in case
14486             var b = this.bindings;
14487             for(var i = 0, len = b.length; i < len; i++){
14488                 b[i].call(this, e);
14489             }
14490             }
14491         },
14492         
14493         /**
14494          * Returns true if this KeyMap is enabled
14495          * @return {Boolean} 
14496          */
14497         isEnabled : function(){
14498             return this.enabled;  
14499         },
14500         
14501         /**
14502          * Enables this KeyMap
14503          */
14504         enable: function(){
14505                 if(!this.enabled){
14506                     this.el.on(this.eventName, this.handleKeyDown, this);
14507                     this.enabled = true;
14508                 }
14509         },
14510
14511         /**
14512          * Disable this KeyMap
14513          */
14514         disable: function(){
14515                 if(this.enabled){
14516                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14517                     this.enabled = false;
14518                 }
14519         }
14520 };/*
14521  * Based on:
14522  * Ext JS Library 1.1.1
14523  * Copyright(c) 2006-2007, Ext JS, LLC.
14524  *
14525  * Originally Released Under LGPL - original licence link has changed is not relivant.
14526  *
14527  * Fork - LGPL
14528  * <script type="text/javascript">
14529  */
14530
14531  
14532 /**
14533  * @class Roo.util.TextMetrics
14534  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14535  * wide, in pixels, a given block of text will be.
14536  * @singleton
14537  */
14538 Roo.util.TextMetrics = function(){
14539     var shared;
14540     return {
14541         /**
14542          * Measures the size of the specified text
14543          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14544          * that can affect the size of the rendered text
14545          * @param {String} text The text to measure
14546          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14547          * in order to accurately measure the text height
14548          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14549          */
14550         measure : function(el, text, fixedWidth){
14551             if(!shared){
14552                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14553             }
14554             shared.bind(el);
14555             shared.setFixedWidth(fixedWidth || 'auto');
14556             return shared.getSize(text);
14557         },
14558
14559         /**
14560          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14561          * the overhead of multiple calls to initialize the style properties on each measurement.
14562          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14563          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14564          * in order to accurately measure the text height
14565          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14566          */
14567         createInstance : function(el, fixedWidth){
14568             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14569         }
14570     };
14571 }();
14572
14573  
14574
14575 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14576     var ml = new Roo.Element(document.createElement('div'));
14577     document.body.appendChild(ml.dom);
14578     ml.position('absolute');
14579     ml.setLeftTop(-1000, -1000);
14580     ml.hide();
14581
14582     if(fixedWidth){
14583         ml.setWidth(fixedWidth);
14584     }
14585      
14586     var instance = {
14587         /**
14588          * Returns the size of the specified text based on the internal element's style and width properties
14589          * @memberOf Roo.util.TextMetrics.Instance#
14590          * @param {String} text The text to measure
14591          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14592          */
14593         getSize : function(text){
14594             ml.update(text);
14595             var s = ml.getSize();
14596             ml.update('');
14597             return s;
14598         },
14599
14600         /**
14601          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14602          * that can affect the size of the rendered text
14603          * @memberOf Roo.util.TextMetrics.Instance#
14604          * @param {String/HTMLElement} el The element, dom node or id
14605          */
14606         bind : function(el){
14607             ml.setStyle(
14608                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14609             );
14610         },
14611
14612         /**
14613          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14614          * to set a fixed width in order to accurately measure the text height.
14615          * @memberOf Roo.util.TextMetrics.Instance#
14616          * @param {Number} width The width to set on the element
14617          */
14618         setFixedWidth : function(width){
14619             ml.setWidth(width);
14620         },
14621
14622         /**
14623          * Returns the measured width of the specified text
14624          * @memberOf Roo.util.TextMetrics.Instance#
14625          * @param {String} text The text to measure
14626          * @return {Number} width The width in pixels
14627          */
14628         getWidth : function(text){
14629             ml.dom.style.width = 'auto';
14630             return this.getSize(text).width;
14631         },
14632
14633         /**
14634          * Returns the measured height of the specified text.  For multiline text, be sure to call
14635          * {@link #setFixedWidth} if necessary.
14636          * @memberOf Roo.util.TextMetrics.Instance#
14637          * @param {String} text The text to measure
14638          * @return {Number} height The height in pixels
14639          */
14640         getHeight : function(text){
14641             return this.getSize(text).height;
14642         }
14643     };
14644
14645     instance.bind(bindTo);
14646
14647     return instance;
14648 };
14649
14650 // backwards compat
14651 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14652  * Based on:
14653  * Ext JS Library 1.1.1
14654  * Copyright(c) 2006-2007, Ext JS, LLC.
14655  *
14656  * Originally Released Under LGPL - original licence link has changed is not relivant.
14657  *
14658  * Fork - LGPL
14659  * <script type="text/javascript">
14660  */
14661
14662 /**
14663  * @class Roo.state.Provider
14664  * Abstract base class for state provider implementations. This class provides methods
14665  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14666  * Provider interface.
14667  */
14668 Roo.state.Provider = function(){
14669     /**
14670      * @event statechange
14671      * Fires when a state change occurs.
14672      * @param {Provider} this This state provider
14673      * @param {String} key The state key which was changed
14674      * @param {String} value The encoded value for the state
14675      */
14676     this.addEvents({
14677         "statechange": true
14678     });
14679     this.state = {};
14680     Roo.state.Provider.superclass.constructor.call(this);
14681 };
14682 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14683     /**
14684      * Returns the current value for a key
14685      * @param {String} name The key name
14686      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14687      * @return {Mixed} The state data
14688      */
14689     get : function(name, defaultValue){
14690         return typeof this.state[name] == "undefined" ?
14691             defaultValue : this.state[name];
14692     },
14693     
14694     /**
14695      * Clears a value from the state
14696      * @param {String} name The key name
14697      */
14698     clear : function(name){
14699         delete this.state[name];
14700         this.fireEvent("statechange", this, name, null);
14701     },
14702     
14703     /**
14704      * Sets the value for a key
14705      * @param {String} name The key name
14706      * @param {Mixed} value The value to set
14707      */
14708     set : function(name, value){
14709         this.state[name] = value;
14710         this.fireEvent("statechange", this, name, value);
14711     },
14712     
14713     /**
14714      * Decodes a string previously encoded with {@link #encodeValue}.
14715      * @param {String} value The value to decode
14716      * @return {Mixed} The decoded value
14717      */
14718     decodeValue : function(cookie){
14719         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14720         var matches = re.exec(unescape(cookie));
14721         if(!matches || !matches[1]) return; // non state cookie
14722         var type = matches[1];
14723         var v = matches[2];
14724         switch(type){
14725             case "n":
14726                 return parseFloat(v);
14727             case "d":
14728                 return new Date(Date.parse(v));
14729             case "b":
14730                 return (v == "1");
14731             case "a":
14732                 var all = [];
14733                 var values = v.split("^");
14734                 for(var i = 0, len = values.length; i < len; i++){
14735                     all.push(this.decodeValue(values[i]));
14736                 }
14737                 return all;
14738            case "o":
14739                 var all = {};
14740                 var values = v.split("^");
14741                 for(var i = 0, len = values.length; i < len; i++){
14742                     var kv = values[i].split("=");
14743                     all[kv[0]] = this.decodeValue(kv[1]);
14744                 }
14745                 return all;
14746            default:
14747                 return v;
14748         }
14749     },
14750     
14751     /**
14752      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14753      * @param {Mixed} value The value to encode
14754      * @return {String} The encoded value
14755      */
14756     encodeValue : function(v){
14757         var enc;
14758         if(typeof v == "number"){
14759             enc = "n:" + v;
14760         }else if(typeof v == "boolean"){
14761             enc = "b:" + (v ? "1" : "0");
14762         }else if(v instanceof Date){
14763             enc = "d:" + v.toGMTString();
14764         }else if(v instanceof Array){
14765             var flat = "";
14766             for(var i = 0, len = v.length; i < len; i++){
14767                 flat += this.encodeValue(v[i]);
14768                 if(i != len-1) flat += "^";
14769             }
14770             enc = "a:" + flat;
14771         }else if(typeof v == "object"){
14772             var flat = "";
14773             for(var key in v){
14774                 if(typeof v[key] != "function"){
14775                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14776                 }
14777             }
14778             enc = "o:" + flat.substring(0, flat.length-1);
14779         }else{
14780             enc = "s:" + v;
14781         }
14782         return escape(enc);        
14783     }
14784 });
14785
14786 /*
14787  * Based on:
14788  * Ext JS Library 1.1.1
14789  * Copyright(c) 2006-2007, Ext JS, LLC.
14790  *
14791  * Originally Released Under LGPL - original licence link has changed is not relivant.
14792  *
14793  * Fork - LGPL
14794  * <script type="text/javascript">
14795  */
14796 /**
14797  * @class Roo.state.Manager
14798  * This is the global state manager. By default all components that are "state aware" check this class
14799  * for state information if you don't pass them a custom state provider. In order for this class
14800  * to be useful, it must be initialized with a provider when your application initializes.
14801  <pre><code>
14802 // in your initialization function
14803 init : function(){
14804    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14805    ...
14806    // supposed you have a {@link Roo.BorderLayout}
14807    var layout = new Roo.BorderLayout(...);
14808    layout.restoreState();
14809    // or a {Roo.BasicDialog}
14810    var dialog = new Roo.BasicDialog(...);
14811    dialog.restoreState();
14812  </code></pre>
14813  * @singleton
14814  */
14815 Roo.state.Manager = function(){
14816     var provider = new Roo.state.Provider();
14817     
14818     return {
14819         /**
14820          * Configures the default state provider for your application
14821          * @param {Provider} stateProvider The state provider to set
14822          */
14823         setProvider : function(stateProvider){
14824             provider = stateProvider;
14825         },
14826         
14827         /**
14828          * Returns the current value for a key
14829          * @param {String} name The key name
14830          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14831          * @return {Mixed} The state data
14832          */
14833         get : function(key, defaultValue){
14834             return provider.get(key, defaultValue);
14835         },
14836         
14837         /**
14838          * Sets the value for a key
14839          * @param {String} name The key name
14840          * @param {Mixed} value The state data
14841          */
14842          set : function(key, value){
14843             provider.set(key, value);
14844         },
14845         
14846         /**
14847          * Clears a value from the state
14848          * @param {String} name The key name
14849          */
14850         clear : function(key){
14851             provider.clear(key);
14852         },
14853         
14854         /**
14855          * Gets the currently configured state provider
14856          * @return {Provider} The state provider
14857          */
14858         getProvider : function(){
14859             return provider;
14860         }
14861     };
14862 }();
14863 /*
14864  * Based on:
14865  * Ext JS Library 1.1.1
14866  * Copyright(c) 2006-2007, Ext JS, LLC.
14867  *
14868  * Originally Released Under LGPL - original licence link has changed is not relivant.
14869  *
14870  * Fork - LGPL
14871  * <script type="text/javascript">
14872  */
14873 /**
14874  * @class Roo.state.CookieProvider
14875  * @extends Roo.state.Provider
14876  * The default Provider implementation which saves state via cookies.
14877  * <br />Usage:
14878  <pre><code>
14879    var cp = new Roo.state.CookieProvider({
14880        path: "/cgi-bin/",
14881        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14882        domain: "roojs.com"
14883    })
14884    Roo.state.Manager.setProvider(cp);
14885  </code></pre>
14886  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14887  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14888  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14889  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14890  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14891  * domain the page is running on including the 'www' like 'www.roojs.com')
14892  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14893  * @constructor
14894  * Create a new CookieProvider
14895  * @param {Object} config The configuration object
14896  */
14897 Roo.state.CookieProvider = function(config){
14898     Roo.state.CookieProvider.superclass.constructor.call(this);
14899     this.path = "/";
14900     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14901     this.domain = null;
14902     this.secure = false;
14903     Roo.apply(this, config);
14904     this.state = this.readCookies();
14905 };
14906
14907 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14908     // private
14909     set : function(name, value){
14910         if(typeof value == "undefined" || value === null){
14911             this.clear(name);
14912             return;
14913         }
14914         this.setCookie(name, value);
14915         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14916     },
14917
14918     // private
14919     clear : function(name){
14920         this.clearCookie(name);
14921         Roo.state.CookieProvider.superclass.clear.call(this, name);
14922     },
14923
14924     // private
14925     readCookies : function(){
14926         var cookies = {};
14927         var c = document.cookie + ";";
14928         var re = /\s?(.*?)=(.*?);/g;
14929         var matches;
14930         while((matches = re.exec(c)) != null){
14931             var name = matches[1];
14932             var value = matches[2];
14933             if(name && name.substring(0,3) == "ys-"){
14934                 cookies[name.substr(3)] = this.decodeValue(value);
14935             }
14936         }
14937         return cookies;
14938     },
14939
14940     // private
14941     setCookie : function(name, value){
14942         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14943            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14944            ((this.path == null) ? "" : ("; path=" + this.path)) +
14945            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14946            ((this.secure == true) ? "; secure" : "");
14947     },
14948
14949     // private
14950     clearCookie : function(name){
14951         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14952            ((this.path == null) ? "" : ("; path=" + this.path)) +
14953            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14954            ((this.secure == true) ? "; secure" : "");
14955     }
14956 });