roojs-core.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",
650                 "Roo.app", "Roo.ux",
651                 "Roo.bootstrap",
652                 "Roo.boostrap.dash");
653 /*
654  * Based on:
655  * Ext JS Library 1.1.1
656  * Copyright(c) 2006-2007, Ext JS, LLC.
657  *
658  * Originally Released Under LGPL - original licence link has changed is not relivant.
659  *
660  * Fork - LGPL
661  * <script type="text/javascript">
662  */
663
664 (function() {    
665     // wrappedn so fnCleanup is not in global scope...
666     if(Roo.isIE) {
667         function fnCleanUp() {
668             var p = Function.prototype;
669             delete p.createSequence;
670             delete p.defer;
671             delete p.createDelegate;
672             delete p.createCallback;
673             delete p.createInterceptor;
674
675             window.detachEvent("onunload", fnCleanUp);
676         }
677         window.attachEvent("onunload", fnCleanUp);
678     }
679 })();
680
681
682 /**
683  * @class Function
684  * These functions are available on every Function object (any JavaScript function).
685  */
686 Roo.apply(Function.prototype, {
687      /**
688      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
689      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
690      * Will create a function that is bound to those 2 args.
691      * @return {Function} The new function
692     */
693     createCallback : function(/*args...*/){
694         // make args available, in function below
695         var args = arguments;
696         var method = this;
697         return function() {
698             return method.apply(window, args);
699         };
700     },
701
702     /**
703      * Creates a delegate (callback) that sets the scope to obj.
704      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
705      * Will create a function that is automatically scoped to this.
706      * @param {Object} obj (optional) The object for which the scope is set
707      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
708      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
709      *                                             if a number the args are inserted at the specified position
710      * @return {Function} The new function
711      */
712     createDelegate : function(obj, args, appendArgs){
713         var method = this;
714         return function() {
715             var callArgs = args || arguments;
716             if(appendArgs === true){
717                 callArgs = Array.prototype.slice.call(arguments, 0);
718                 callArgs = callArgs.concat(args);
719             }else if(typeof appendArgs == "number"){
720                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
721                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
722                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
723             }
724             return method.apply(obj || window, callArgs);
725         };
726     },
727
728     /**
729      * Calls this function after the number of millseconds specified.
730      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
731      * @param {Object} obj (optional) The object for which the scope is set
732      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
733      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
734      *                                             if a number the args are inserted at the specified position
735      * @return {Number} The timeout id that can be used with clearTimeout
736      */
737     defer : function(millis, obj, args, appendArgs){
738         var fn = this.createDelegate(obj, args, appendArgs);
739         if(millis){
740             return setTimeout(fn, millis);
741         }
742         fn();
743         return 0;
744     },
745     /**
746      * Create a combined function call sequence of the original function + the passed function.
747      * The resulting function returns the results of the original function.
748      * The passed fcn is called with the parameters of the original function
749      * @param {Function} fcn The function to sequence
750      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
751      * @return {Function} The new function
752      */
753     createSequence : function(fcn, scope){
754         if(typeof fcn != "function"){
755             return this;
756         }
757         var method = this;
758         return function() {
759             var retval = method.apply(this || window, arguments);
760             fcn.apply(scope || this || window, arguments);
761             return retval;
762         };
763     },
764
765     /**
766      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
767      * The resulting function returns the results of the original function.
768      * The passed fcn is called with the parameters of the original function.
769      * @addon
770      * @param {Function} fcn The function to call before the original
771      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
772      * @return {Function} The new function
773      */
774     createInterceptor : function(fcn, scope){
775         if(typeof fcn != "function"){
776             return this;
777         }
778         var method = this;
779         return function() {
780             fcn.target = this;
781             fcn.method = method;
782             if(fcn.apply(scope || this || window, arguments) === false){
783                 return;
784             }
785             return method.apply(this || window, arguments);
786         };
787     }
788 });
789 /*
790  * Based on:
791  * Ext JS Library 1.1.1
792  * Copyright(c) 2006-2007, Ext JS, LLC.
793  *
794  * Originally Released Under LGPL - original licence link has changed is not relivant.
795  *
796  * Fork - LGPL
797  * <script type="text/javascript">
798  */
799
800 Roo.applyIf(String, {
801     
802     /** @scope String */
803     
804     /**
805      * Escapes the passed string for ' and \
806      * @param {String} string The string to escape
807      * @return {String} The escaped string
808      * @static
809      */
810     escape : function(string) {
811         return string.replace(/('|\\)/g, "\\$1");
812     },
813
814     /**
815      * Pads the left side of a string with a specified character.  This is especially useful
816      * for normalizing number and date strings.  Example usage:
817      * <pre><code>
818 var s = String.leftPad('123', 5, '0');
819 // s now contains the string: '00123'
820 </code></pre>
821      * @param {String} string The original string
822      * @param {Number} size The total length of the output string
823      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
824      * @return {String} The padded string
825      * @static
826      */
827     leftPad : function (val, size, ch) {
828         var result = new String(val);
829         if(ch === null || ch === undefined || ch === '') {
830             ch = " ";
831         }
832         while (result.length < size) {
833             result = ch + result;
834         }
835         return result;
836     },
837
838     /**
839      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
840      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
841      * <pre><code>
842 var cls = 'my-class', text = 'Some text';
843 var s = String.format('<div class="{0}">{1}</div>', cls, text);
844 // s now contains the string: '<div class="my-class">Some text</div>'
845 </code></pre>
846      * @param {String} string The tokenized string to be formatted
847      * @param {String} value1 The value to replace token {0}
848      * @param {String} value2 Etc...
849      * @return {String} The formatted string
850      * @static
851      */
852     format : function(format){
853         var args = Array.prototype.slice.call(arguments, 1);
854         return format.replace(/\{(\d+)\}/g, function(m, i){
855             return Roo.util.Format.htmlEncode(args[i]);
856         });
857     }
858 });
859
860 /**
861  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
862  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
863  * they are already different, the first value passed in is returned.  Note that this method returns the new value
864  * but does not change the current string.
865  * <pre><code>
866 // alternate sort directions
867 sort = sort.toggle('ASC', 'DESC');
868
869 // instead of conditional logic:
870 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
871 </code></pre>
872  * @param {String} value The value to compare to the current string
873  * @param {String} other The new value to use if the string already equals the first value passed in
874  * @return {String} The new value
875  */
876  
877 String.prototype.toggle = function(value, other){
878     return this == value ? other : value;
879 };/*
880  * Based on:
881  * Ext JS Library 1.1.1
882  * Copyright(c) 2006-2007, Ext JS, LLC.
883  *
884  * Originally Released Under LGPL - original licence link has changed is not relivant.
885  *
886  * Fork - LGPL
887  * <script type="text/javascript">
888  */
889
890  /**
891  * @class Number
892  */
893 Roo.applyIf(Number.prototype, {
894     /**
895      * Checks whether or not the current number is within a desired range.  If the number is already within the
896      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
897      * exceeded.  Note that this method returns the constrained value but does not change the current number.
898      * @param {Number} min The minimum number in the range
899      * @param {Number} max The maximum number in the range
900      * @return {Number} The constrained value if outside the range, otherwise the current value
901      */
902     constrain : function(min, max){
903         return Math.min(Math.max(this, min), max);
904     }
905 });/*
906  * Based on:
907  * Ext JS Library 1.1.1
908  * Copyright(c) 2006-2007, Ext JS, LLC.
909  *
910  * Originally Released Under LGPL - original licence link has changed is not relivant.
911  *
912  * Fork - LGPL
913  * <script type="text/javascript">
914  */
915  /**
916  * @class Array
917  */
918 Roo.applyIf(Array.prototype, {
919     /**
920      * Checks whether or not the specified object exists in the array.
921      * @param {Object} o The object to check for
922      * @return {Number} The index of o in the array (or -1 if it is not found)
923      */
924     indexOf : function(o){
925        for (var i = 0, len = this.length; i < len; i++){
926               if(this[i] == o) return i;
927        }
928            return -1;
929     },
930
931     /**
932      * Removes the specified object from the array.  If the object is not found nothing happens.
933      * @param {Object} o The object to remove
934      */
935     remove : function(o){
936        var index = this.indexOf(o);
937        if(index != -1){
938            this.splice(index, 1);
939        }
940     },
941     /**
942      * Map (JS 1.6 compatibility)
943      * @param {Function} function  to call
944      */
945     map : function(fun )
946     {
947         var len = this.length >>> 0;
948         if (typeof fun != "function")
949             throw new TypeError();
950
951         var res = new Array(len);
952         var thisp = arguments[1];
953         for (var i = 0; i < len; i++)
954         {
955             if (i in this)
956                 res[i] = fun.call(thisp, this[i], i, this);
957         }
958
959         return res;
960     }
961     
962 });
963
964
965  /*
966  * Based on:
967  * Ext JS Library 1.1.1
968  * Copyright(c) 2006-2007, Ext JS, LLC.
969  *
970  * Originally Released Under LGPL - original licence link has changed is not relivant.
971  *
972  * Fork - LGPL
973  * <script type="text/javascript">
974  */
975
976 /**
977  * @class Date
978  *
979  * The date parsing and format syntax is a subset of
980  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
981  * supported will provide results equivalent to their PHP versions.
982  *
983  * Following is the list of all currently supported formats:
984  *<pre>
985 Sample date:
986 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
987
988 Format  Output      Description
989 ------  ----------  --------------------------------------------------------------
990   d      10         Day of the month, 2 digits with leading zeros
991   D      Wed        A textual representation of a day, three letters
992   j      10         Day of the month without leading zeros
993   l      Wednesday  A full textual representation of the day of the week
994   S      th         English ordinal day of month suffix, 2 chars (use with j)
995   w      3          Numeric representation of the day of the week
996   z      9          The julian date, or day of the year (0-365)
997   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
998   F      January    A full textual representation of the month
999   m      01         Numeric representation of a month, with leading zeros
1000   M      Jan        Month name abbreviation, three letters
1001   n      1          Numeric representation of a month, without leading zeros
1002   t      31         Number of days in the given month
1003   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1004   Y      2007       A full numeric representation of a year, 4 digits
1005   y      07         A two digit representation of a year
1006   a      pm         Lowercase Ante meridiem and Post meridiem
1007   A      PM         Uppercase Ante meridiem and Post meridiem
1008   g      3          12-hour format of an hour without leading zeros
1009   G      15         24-hour format of an hour without leading zeros
1010   h      03         12-hour format of an hour with leading zeros
1011   H      15         24-hour format of an hour with leading zeros
1012   i      05         Minutes with leading zeros
1013   s      01         Seconds, with leading zeros
1014   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1015   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1016   T      CST        Timezone setting of the machine running the code
1017   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1018 </pre>
1019  *
1020  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1021  * <pre><code>
1022 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1023 document.write(dt.format('Y-m-d'));                         //2007-01-10
1024 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1025 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
1026  </code></pre>
1027  *
1028  * Here are some standard date/time patterns that you might find helpful.  They
1029  * are not part of the source of Date.js, but to use them you can simply copy this
1030  * block of code into any script that is included after Date.js and they will also become
1031  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1032  * <pre><code>
1033 Date.patterns = {
1034     ISO8601Long:"Y-m-d H:i:s",
1035     ISO8601Short:"Y-m-d",
1036     ShortDate: "n/j/Y",
1037     LongDate: "l, F d, Y",
1038     FullDateTime: "l, F d, Y g:i:s A",
1039     MonthDay: "F d",
1040     ShortTime: "g:i A",
1041     LongTime: "g:i:s A",
1042     SortableDateTime: "Y-m-d\\TH:i:s",
1043     UniversalSortableDateTime: "Y-m-d H:i:sO",
1044     YearMonth: "F, Y"
1045 };
1046 </code></pre>
1047  *
1048  * Example usage:
1049  * <pre><code>
1050 var dt = new Date();
1051 document.write(dt.format(Date.patterns.ShortDate));
1052  </code></pre>
1053  */
1054
1055 /*
1056  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1057  * They generate precompiled functions from date formats instead of parsing and
1058  * processing the pattern every time you format a date.  These functions are available
1059  * on every Date object (any javascript function).
1060  *
1061  * The original article and download are here:
1062  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1063  *
1064  */
1065  
1066  
1067  // was in core
1068 /**
1069  Returns the number of milliseconds between this date and date
1070  @param {Date} date (optional) Defaults to now
1071  @return {Number} The diff in milliseconds
1072  @member Date getElapsed
1073  */
1074 Date.prototype.getElapsed = function(date) {
1075         return Math.abs((date || new Date()).getTime()-this.getTime());
1076 };
1077 // was in date file..
1078
1079
1080 // private
1081 Date.parseFunctions = {count:0};
1082 // private
1083 Date.parseRegexes = [];
1084 // private
1085 Date.formatFunctions = {count:0};
1086
1087 // private
1088 Date.prototype.dateFormat = function(format) {
1089     if (Date.formatFunctions[format] == null) {
1090         Date.createNewFormat(format);
1091     }
1092     var func = Date.formatFunctions[format];
1093     return this[func]();
1094 };
1095
1096
1097 /**
1098  * Formats a date given the supplied format string
1099  * @param {String} format The format string
1100  * @return {String} The formatted date
1101  * @method
1102  */
1103 Date.prototype.format = Date.prototype.dateFormat;
1104
1105 // private
1106 Date.createNewFormat = function(format) {
1107     var funcName = "format" + Date.formatFunctions.count++;
1108     Date.formatFunctions[format] = funcName;
1109     var code = "Date.prototype." + funcName + " = function(){return ";
1110     var special = false;
1111     var ch = '';
1112     for (var i = 0; i < format.length; ++i) {
1113         ch = format.charAt(i);
1114         if (!special && ch == "\\") {
1115             special = true;
1116         }
1117         else if (special) {
1118             special = false;
1119             code += "'" + String.escape(ch) + "' + ";
1120         }
1121         else {
1122             code += Date.getFormatCode(ch);
1123         }
1124     }
1125     /** eval:var:zzzzzzzzzzzzz */
1126     eval(code.substring(0, code.length - 3) + ";}");
1127 };
1128
1129 // private
1130 Date.getFormatCode = function(character) {
1131     switch (character) {
1132     case "d":
1133         return "String.leftPad(this.getDate(), 2, '0') + ";
1134     case "D":
1135         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1136     case "j":
1137         return "this.getDate() + ";
1138     case "l":
1139         return "Date.dayNames[this.getDay()] + ";
1140     case "S":
1141         return "this.getSuffix() + ";
1142     case "w":
1143         return "this.getDay() + ";
1144     case "z":
1145         return "this.getDayOfYear() + ";
1146     case "W":
1147         return "this.getWeekOfYear() + ";
1148     case "F":
1149         return "Date.monthNames[this.getMonth()] + ";
1150     case "m":
1151         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1152     case "M":
1153         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1154     case "n":
1155         return "(this.getMonth() + 1) + ";
1156     case "t":
1157         return "this.getDaysInMonth() + ";
1158     case "L":
1159         return "(this.isLeapYear() ? 1 : 0) + ";
1160     case "Y":
1161         return "this.getFullYear() + ";
1162     case "y":
1163         return "('' + this.getFullYear()).substring(2, 4) + ";
1164     case "a":
1165         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1166     case "A":
1167         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1168     case "g":
1169         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1170     case "G":
1171         return "this.getHours() + ";
1172     case "h":
1173         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1174     case "H":
1175         return "String.leftPad(this.getHours(), 2, '0') + ";
1176     case "i":
1177         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1178     case "s":
1179         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1180     case "O":
1181         return "this.getGMTOffset() + ";
1182     case "P":
1183         return "this.getGMTColonOffset() + ";
1184     case "T":
1185         return "this.getTimezone() + ";
1186     case "Z":
1187         return "(this.getTimezoneOffset() * -60) + ";
1188     default:
1189         return "'" + String.escape(character) + "' + ";
1190     }
1191 };
1192
1193 /**
1194  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1195  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1196  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1197  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1198  * string or the parse operation will fail.
1199  * Example Usage:
1200 <pre><code>
1201 //dt = Fri May 25 2007 (current date)
1202 var dt = new Date();
1203
1204 //dt = Thu May 25 2006 (today's month/day in 2006)
1205 dt = Date.parseDate("2006", "Y");
1206
1207 //dt = Sun Jan 15 2006 (all date parts specified)
1208 dt = Date.parseDate("2006-1-15", "Y-m-d");
1209
1210 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1211 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1212 </code></pre>
1213  * @param {String} input The unparsed date as a string
1214  * @param {String} format The format the date is in
1215  * @return {Date} The parsed date
1216  * @static
1217  */
1218 Date.parseDate = function(input, format) {
1219     if (Date.parseFunctions[format] == null) {
1220         Date.createParser(format);
1221     }
1222     var func = Date.parseFunctions[format];
1223     return Date[func](input);
1224 };
1225 /**
1226  * @private
1227  */
1228 Date.createParser = function(format) {
1229     var funcName = "parse" + Date.parseFunctions.count++;
1230     var regexNum = Date.parseRegexes.length;
1231     var currentGroup = 1;
1232     Date.parseFunctions[format] = funcName;
1233
1234     var code = "Date." + funcName + " = function(input){\n"
1235         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1236         + "var d = new Date();\n"
1237         + "y = d.getFullYear();\n"
1238         + "m = d.getMonth();\n"
1239         + "d = d.getDate();\n"
1240         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1241         + "if (results && results.length > 0) {";
1242     var regex = "";
1243
1244     var special = false;
1245     var ch = '';
1246     for (var i = 0; i < format.length; ++i) {
1247         ch = format.charAt(i);
1248         if (!special && ch == "\\") {
1249             special = true;
1250         }
1251         else if (special) {
1252             special = false;
1253             regex += String.escape(ch);
1254         }
1255         else {
1256             var obj = Date.formatCodeToRegex(ch, currentGroup);
1257             currentGroup += obj.g;
1258             regex += obj.s;
1259             if (obj.g && obj.c) {
1260                 code += obj.c;
1261             }
1262         }
1263     }
1264
1265     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1266         + "{v = new Date(y, m, d, h, i, s);}\n"
1267         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1268         + "{v = new Date(y, m, d, h, i);}\n"
1269         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1270         + "{v = new Date(y, m, d, h);}\n"
1271         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1272         + "{v = new Date(y, m, d);}\n"
1273         + "else if (y >= 0 && m >= 0)\n"
1274         + "{v = new Date(y, m);}\n"
1275         + "else if (y >= 0)\n"
1276         + "{v = new Date(y);}\n"
1277         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1278         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1279         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1280         + ";}";
1281
1282     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1283     /** eval:var:zzzzzzzzzzzzz */
1284     eval(code);
1285 };
1286
1287 // private
1288 Date.formatCodeToRegex = function(character, currentGroup) {
1289     switch (character) {
1290     case "D":
1291         return {g:0,
1292         c:null,
1293         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1294     case "j":
1295         return {g:1,
1296             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1297             s:"(\\d{1,2})"}; // day of month without leading zeroes
1298     case "d":
1299         return {g:1,
1300             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1301             s:"(\\d{2})"}; // day of month with leading zeroes
1302     case "l":
1303         return {g:0,
1304             c:null,
1305             s:"(?:" + Date.dayNames.join("|") + ")"};
1306     case "S":
1307         return {g:0,
1308             c:null,
1309             s:"(?:st|nd|rd|th)"};
1310     case "w":
1311         return {g:0,
1312             c:null,
1313             s:"\\d"};
1314     case "z":
1315         return {g:0,
1316             c:null,
1317             s:"(?:\\d{1,3})"};
1318     case "W":
1319         return {g:0,
1320             c:null,
1321             s:"(?:\\d{2})"};
1322     case "F":
1323         return {g:1,
1324             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1325             s:"(" + Date.monthNames.join("|") + ")"};
1326     case "M":
1327         return {g:1,
1328             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1329             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1330     case "n":
1331         return {g:1,
1332             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1333             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1334     case "m":
1335         return {g:1,
1336             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1337             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1338     case "t":
1339         return {g:0,
1340             c:null,
1341             s:"\\d{1,2}"};
1342     case "L":
1343         return {g:0,
1344             c:null,
1345             s:"(?:1|0)"};
1346     case "Y":
1347         return {g:1,
1348             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349             s:"(\\d{4})"};
1350     case "y":
1351         return {g:1,
1352             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1353                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354             s:"(\\d{1,2})"};
1355     case "a":
1356         return {g:1,
1357             c:"if (results[" + currentGroup + "] == 'am') {\n"
1358                 + "if (h == 12) { h = 0; }\n"
1359                 + "} else { if (h < 12) { h += 12; }}",
1360             s:"(am|pm)"};
1361     case "A":
1362         return {g:1,
1363             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1364                 + "if (h == 12) { h = 0; }\n"
1365                 + "} else { if (h < 12) { h += 12; }}",
1366             s:"(AM|PM)"};
1367     case "g":
1368     case "G":
1369         return {g:1,
1370             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1372     case "h":
1373     case "H":
1374         return {g:1,
1375             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1376             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1377     case "i":
1378         return {g:1,
1379             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380             s:"(\\d{2})"};
1381     case "s":
1382         return {g:1,
1383             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1384             s:"(\\d{2})"};
1385     case "O":
1386         return {g:1,
1387             c:[
1388                 "o = results[", currentGroup, "];\n",
1389                 "var sn = o.substring(0,1);\n", // get + / - sign
1390                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1391                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1392                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1393                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1394             ].join(""),
1395             s:"([+\-]\\d{2,4})"};
1396     
1397     
1398     case "P":
1399         return {g:1,
1400                 c:[
1401                    "o = results[", currentGroup, "];\n",
1402                    "var sn = o.substring(0,1);\n",
1403                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1404                    "var mn = o.substring(4,6) % 60;\n",
1405                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1406                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407             ].join(""),
1408             s:"([+\-]\\d{4})"};
1409     case "T":
1410         return {g:0,
1411             c:null,
1412             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1413     case "Z":
1414         return {g:1,
1415             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1416                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1417             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418     default:
1419         return {g:0,
1420             c:null,
1421             s:String.escape(character)};
1422     }
1423 };
1424
1425 /**
1426  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1427  * @return {String} The abbreviated timezone name (e.g. 'CST')
1428  */
1429 Date.prototype.getTimezone = function() {
1430     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 };
1432
1433 /**
1434  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1435  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1436  */
1437 Date.prototype.getGMTOffset = function() {
1438     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1439         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1440         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 };
1442
1443 /**
1444  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1445  * @return {String} 2-characters representing hours and 2-characters representing minutes
1446  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1447  */
1448 Date.prototype.getGMTColonOffset = function() {
1449         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1450                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1451                 + ":"
1452                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 }
1454
1455 /**
1456  * Get the numeric day number of the year, adjusted for leap year.
1457  * @return {Number} 0 through 364 (365 in leap years)
1458  */
1459 Date.prototype.getDayOfYear = function() {
1460     var num = 0;
1461     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1462     for (var i = 0; i < this.getMonth(); ++i) {
1463         num += Date.daysInMonth[i];
1464     }
1465     return num + this.getDate() - 1;
1466 };
1467
1468 /**
1469  * Get the string representation of the numeric week number of the year
1470  * (equivalent to the format specifier 'W').
1471  * @return {String} '00' through '52'
1472  */
1473 Date.prototype.getWeekOfYear = function() {
1474     // Skip to Thursday of this week
1475     var now = this.getDayOfYear() + (4 - this.getDay());
1476     // Find the first Thursday of the year
1477     var jan1 = new Date(this.getFullYear(), 0, 1);
1478     var then = (7 - jan1.getDay() + 4);
1479     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 };
1481
1482 /**
1483  * Whether or not the current date is in a leap year.
1484  * @return {Boolean} True if the current date is in a leap year, else false
1485  */
1486 Date.prototype.isLeapYear = function() {
1487     var year = this.getFullYear();
1488     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 };
1490
1491 /**
1492  * Get the first day of the current month, adjusted for leap year.  The returned value
1493  * is the numeric day index within the week (0-6) which can be used in conjunction with
1494  * the {@link #monthNames} array to retrieve the textual day name.
1495  * Example:
1496  *<pre><code>
1497 var dt = new Date('1/10/2007');
1498 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1499 </code></pre>
1500  * @return {Number} The day number (0-6)
1501  */
1502 Date.prototype.getFirstDayOfMonth = function() {
1503     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1504     return (day < 0) ? (day + 7) : day;
1505 };
1506
1507 /**
1508  * Get the last day of the current month, adjusted for leap year.  The returned value
1509  * is the numeric day index within the week (0-6) which can be used in conjunction with
1510  * the {@link #monthNames} array to retrieve the textual day name.
1511  * Example:
1512  *<pre><code>
1513 var dt = new Date('1/10/2007');
1514 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1515 </code></pre>
1516  * @return {Number} The day number (0-6)
1517  */
1518 Date.prototype.getLastDayOfMonth = function() {
1519     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1520     return (day < 0) ? (day + 7) : day;
1521 };
1522
1523
1524 /**
1525  * Get the first date of this date's month
1526  * @return {Date}
1527  */
1528 Date.prototype.getFirstDateOfMonth = function() {
1529     return new Date(this.getFullYear(), this.getMonth(), 1);
1530 };
1531
1532 /**
1533  * Get the last date of this date's month
1534  * @return {Date}
1535  */
1536 Date.prototype.getLastDateOfMonth = function() {
1537     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1538 };
1539 /**
1540  * Get the number of days in the current month, adjusted for leap year.
1541  * @return {Number} The number of days in the month
1542  */
1543 Date.prototype.getDaysInMonth = function() {
1544     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1545     return Date.daysInMonth[this.getMonth()];
1546 };
1547
1548 /**
1549  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1550  * @return {String} 'st, 'nd', 'rd' or 'th'
1551  */
1552 Date.prototype.getSuffix = function() {
1553     switch (this.getDate()) {
1554         case 1:
1555         case 21:
1556         case 31:
1557             return "st";
1558         case 2:
1559         case 22:
1560             return "nd";
1561         case 3:
1562         case 23:
1563             return "rd";
1564         default:
1565             return "th";
1566     }
1567 };
1568
1569 // private
1570 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1571
1572 /**
1573  * An array of textual month names.
1574  * Override these values for international dates, for example...
1575  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1576  * @type Array
1577  * @static
1578  */
1579 Date.monthNames =
1580    ["January",
1581     "February",
1582     "March",
1583     "April",
1584     "May",
1585     "June",
1586     "July",
1587     "August",
1588     "September",
1589     "October",
1590     "November",
1591     "December"];
1592
1593 /**
1594  * An array of textual day names.
1595  * Override these values for international dates, for example...
1596  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1597  * @type Array
1598  * @static
1599  */
1600 Date.dayNames =
1601    ["Sunday",
1602     "Monday",
1603     "Tuesday",
1604     "Wednesday",
1605     "Thursday",
1606     "Friday",
1607     "Saturday"];
1608
1609 // private
1610 Date.y2kYear = 50;
1611 // private
1612 Date.monthNumbers = {
1613     Jan:0,
1614     Feb:1,
1615     Mar:2,
1616     Apr:3,
1617     May:4,
1618     Jun:5,
1619     Jul:6,
1620     Aug:7,
1621     Sep:8,
1622     Oct:9,
1623     Nov:10,
1624     Dec:11};
1625
1626 /**
1627  * Creates and returns a new Date instance with the exact same date value as the called instance.
1628  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1629  * variable will also be changed.  When the intention is to create a new variable that will not
1630  * modify the original instance, you should create a clone.
1631  *
1632  * Example of correctly cloning a date:
1633  * <pre><code>
1634 //wrong way:
1635 var orig = new Date('10/1/2006');
1636 var copy = orig;
1637 copy.setDate(5);
1638 document.write(orig);  //returns 'Thu Oct 05 2006'!
1639
1640 //correct way:
1641 var orig = new Date('10/1/2006');
1642 var copy = orig.clone();
1643 copy.setDate(5);
1644 document.write(orig);  //returns 'Thu Oct 01 2006'
1645 </code></pre>
1646  * @return {Date} The new Date instance
1647  */
1648 Date.prototype.clone = function() {
1649         return new Date(this.getTime());
1650 };
1651
1652 /**
1653  * Clears any time information from this date
1654  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1655  @return {Date} this or the clone
1656  */
1657 Date.prototype.clearTime = function(clone){
1658     if(clone){
1659         return this.clone().clearTime();
1660     }
1661     this.setHours(0);
1662     this.setMinutes(0);
1663     this.setSeconds(0);
1664     this.setMilliseconds(0);
1665     return this;
1666 };
1667
1668 // private
1669 // safari setMonth is broken
1670 if(Roo.isSafari){
1671     Date.brokenSetMonth = Date.prototype.setMonth;
1672         Date.prototype.setMonth = function(num){
1673                 if(num <= -1){
1674                         var n = Math.ceil(-num);
1675                         var back_year = Math.ceil(n/12);
1676                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1677                         this.setFullYear(this.getFullYear() - back_year);
1678                         return Date.brokenSetMonth.call(this, month);
1679                 } else {
1680                         return Date.brokenSetMonth.apply(this, arguments);
1681                 }
1682         };
1683 }
1684
1685 /** Date interval constant 
1686 * @static 
1687 * @type String */
1688 Date.MILLI = "ms";
1689 /** Date interval constant 
1690 * @static 
1691 * @type String */
1692 Date.SECOND = "s";
1693 /** Date interval constant 
1694 * @static 
1695 * @type String */
1696 Date.MINUTE = "mi";
1697 /** Date interval constant 
1698 * @static 
1699 * @type String */
1700 Date.HOUR = "h";
1701 /** Date interval constant 
1702 * @static 
1703 * @type String */
1704 Date.DAY = "d";
1705 /** Date interval constant 
1706 * @static 
1707 * @type String */
1708 Date.MONTH = "mo";
1709 /** Date interval constant 
1710 * @static 
1711 * @type String */
1712 Date.YEAR = "y";
1713
1714 /**
1715  * Provides a convenient method of performing basic date arithmetic.  This method
1716  * does not modify the Date instance being called - it creates and returns
1717  * a new Date instance containing the resulting date value.
1718  *
1719  * Examples:
1720  * <pre><code>
1721 //Basic usage:
1722 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1723 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1724
1725 //Negative values will subtract correctly:
1726 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1727 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1728
1729 //You can even chain several calls together in one line!
1730 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1731 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1732  </code></pre>
1733  *
1734  * @param {String} interval   A valid date interval enum value
1735  * @param {Number} value      The amount to add to the current date
1736  * @return {Date} The new Date instance
1737  */
1738 Date.prototype.add = function(interval, value){
1739   var d = this.clone();
1740   if (!interval || value === 0) return d;
1741   switch(interval.toLowerCase()){
1742     case Date.MILLI:
1743       d.setMilliseconds(this.getMilliseconds() + value);
1744       break;
1745     case Date.SECOND:
1746       d.setSeconds(this.getSeconds() + value);
1747       break;
1748     case Date.MINUTE:
1749       d.setMinutes(this.getMinutes() + value);
1750       break;
1751     case Date.HOUR:
1752       d.setHours(this.getHours() + value);
1753       break;
1754     case Date.DAY:
1755       d.setDate(this.getDate() + value);
1756       break;
1757     case Date.MONTH:
1758       var day = this.getDate();
1759       if(day > 28){
1760           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1761       }
1762       d.setDate(day);
1763       d.setMonth(this.getMonth() + value);
1764       break;
1765     case Date.YEAR:
1766       d.setFullYear(this.getFullYear() + value);
1767       break;
1768   }
1769   return d;
1770 };
1771 /*
1772  * Based on:
1773  * Ext JS Library 1.1.1
1774  * Copyright(c) 2006-2007, Ext JS, LLC.
1775  *
1776  * Originally Released Under LGPL - original licence link has changed is not relivant.
1777  *
1778  * Fork - LGPL
1779  * <script type="text/javascript">
1780  */
1781
1782 /**
1783  * @class Roo.lib.Dom
1784  * @static
1785  * 
1786  * Dom utils (from YIU afaik)
1787  * 
1788  **/
1789 Roo.lib.Dom = {
1790     /**
1791      * Get the view width
1792      * @param {Boolean} full True will get the full document, otherwise it's the view width
1793      * @return {Number} The width
1794      */
1795      
1796     getViewWidth : function(full) {
1797         return full ? this.getDocumentWidth() : this.getViewportWidth();
1798     },
1799     /**
1800      * Get the view height
1801      * @param {Boolean} full True will get the full document, otherwise it's the view height
1802      * @return {Number} The height
1803      */
1804     getViewHeight : function(full) {
1805         return full ? this.getDocumentHeight() : this.getViewportHeight();
1806     },
1807
1808     getDocumentHeight: function() {
1809         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1810         return Math.max(scrollHeight, this.getViewportHeight());
1811     },
1812
1813     getDocumentWidth: function() {
1814         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1815         return Math.max(scrollWidth, this.getViewportWidth());
1816     },
1817
1818     getViewportHeight: function() {
1819         var height = self.innerHeight;
1820         var mode = document.compatMode;
1821
1822         if ((mode || Roo.isIE) && !Roo.isOpera) {
1823             height = (mode == "CSS1Compat") ?
1824                      document.documentElement.clientHeight :
1825                      document.body.clientHeight;
1826         }
1827
1828         return height;
1829     },
1830
1831     getViewportWidth: function() {
1832         var width = self.innerWidth;
1833         var mode = document.compatMode;
1834
1835         if (mode || Roo.isIE) {
1836             width = (mode == "CSS1Compat") ?
1837                     document.documentElement.clientWidth :
1838                     document.body.clientWidth;
1839         }
1840         return width;
1841     },
1842
1843     isAncestor : function(p, c) {
1844         p = Roo.getDom(p);
1845         c = Roo.getDom(c);
1846         if (!p || !c) {
1847             return false;
1848         }
1849
1850         if (p.contains && !Roo.isSafari) {
1851             return p.contains(c);
1852         } else if (p.compareDocumentPosition) {
1853             return !!(p.compareDocumentPosition(c) & 16);
1854         } else {
1855             var parent = c.parentNode;
1856             while (parent) {
1857                 if (parent == p) {
1858                     return true;
1859                 }
1860                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1861                     return false;
1862                 }
1863                 parent = parent.parentNode;
1864             }
1865             return false;
1866         }
1867     },
1868
1869     getRegion : function(el) {
1870         return Roo.lib.Region.getRegion(el);
1871     },
1872
1873     getY : function(el) {
1874         return this.getXY(el)[1];
1875     },
1876
1877     getX : function(el) {
1878         return this.getXY(el)[0];
1879     },
1880
1881     getXY : function(el) {
1882         var p, pe, b, scroll, bd = document.body;
1883         el = Roo.getDom(el);
1884         var fly = Roo.lib.AnimBase.fly;
1885         if (el.getBoundingClientRect) {
1886             b = el.getBoundingClientRect();
1887             scroll = fly(document).getScroll();
1888             return [b.left + scroll.left, b.top + scroll.top];
1889         }
1890         var x = 0, y = 0;
1891
1892         p = el;
1893
1894         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1895
1896         while (p) {
1897
1898             x += p.offsetLeft;
1899             y += p.offsetTop;
1900
1901             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1902                 hasAbsolute = true;
1903             }
1904
1905             if (Roo.isGecko) {
1906                 pe = fly(p);
1907
1908                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1909                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1910
1911
1912                 x += bl;
1913                 y += bt;
1914
1915
1916                 if (p != el && pe.getStyle('overflow') != 'visible') {
1917                     x += bl;
1918                     y += bt;
1919                 }
1920             }
1921             p = p.offsetParent;
1922         }
1923
1924         if (Roo.isSafari && hasAbsolute) {
1925             x -= bd.offsetLeft;
1926             y -= bd.offsetTop;
1927         }
1928
1929         if (Roo.isGecko && !hasAbsolute) {
1930             var dbd = fly(bd);
1931             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1932             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933         }
1934
1935         p = el.parentNode;
1936         while (p && p != bd) {
1937             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1938                 x -= p.scrollLeft;
1939                 y -= p.scrollTop;
1940             }
1941             p = p.parentNode;
1942         }
1943         return [x, y];
1944     },
1945  
1946   
1947
1948
1949     setXY : function(el, xy) {
1950         el = Roo.fly(el, '_setXY');
1951         el.position();
1952         var pts = el.translatePoints(xy);
1953         if (xy[0] !== false) {
1954             el.dom.style.left = pts.left + "px";
1955         }
1956         if (xy[1] !== false) {
1957             el.dom.style.top = pts.top + "px";
1958         }
1959     },
1960
1961     setX : function(el, x) {
1962         this.setXY(el, [x, false]);
1963     },
1964
1965     setY : function(el, y) {
1966         this.setXY(el, [false, y]);
1967     }
1968 };
1969 /*
1970  * Portions of this file are based on pieces of Yahoo User Interface Library
1971  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1972  * YUI licensed under the BSD License:
1973  * http://developer.yahoo.net/yui/license.txt
1974  * <script type="text/javascript">
1975  *
1976  */
1977
1978 Roo.lib.Event = function() {
1979     var loadComplete = false;
1980     var listeners = [];
1981     var unloadListeners = [];
1982     var retryCount = 0;
1983     var onAvailStack = [];
1984     var counter = 0;
1985     var lastError = null;
1986
1987     return {
1988         POLL_RETRYS: 200,
1989         POLL_INTERVAL: 20,
1990         EL: 0,
1991         TYPE: 1,
1992         FN: 2,
1993         WFN: 3,
1994         OBJ: 3,
1995         ADJ_SCOPE: 4,
1996         _interval: null,
1997
1998         startInterval: function() {
1999             if (!this._interval) {
2000                 var self = this;
2001                 var callback = function() {
2002                     self._tryPreloadAttach();
2003                 };
2004                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2005
2006             }
2007         },
2008
2009         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2010             onAvailStack.push({ id:         p_id,
2011                 fn:         p_fn,
2012                 obj:        p_obj,
2013                 override:   p_override,
2014                 checkReady: false    });
2015
2016             retryCount = this.POLL_RETRYS;
2017             this.startInterval();
2018         },
2019
2020
2021         addListener: function(el, eventName, fn) {
2022             el = Roo.getDom(el);
2023             if (!el || !fn) {
2024                 return false;
2025             }
2026
2027             if ("unload" == eventName) {
2028                 unloadListeners[unloadListeners.length] =
2029                 [el, eventName, fn];
2030                 return true;
2031             }
2032
2033             var wrappedFn = function(e) {
2034                 return fn(Roo.lib.Event.getEvent(e));
2035             };
2036
2037             var li = [el, eventName, fn, wrappedFn];
2038
2039             var index = listeners.length;
2040             listeners[index] = li;
2041
2042             this.doAdd(el, eventName, wrappedFn, false);
2043             return true;
2044
2045         },
2046
2047
2048         removeListener: function(el, eventName, fn) {
2049             var i, len;
2050
2051             el = Roo.getDom(el);
2052
2053             if(!fn) {
2054                 return this.purgeElement(el, false, eventName);
2055             }
2056
2057
2058             if ("unload" == eventName) {
2059
2060                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2061                     var li = unloadListeners[i];
2062                     if (li &&
2063                         li[0] == el &&
2064                         li[1] == eventName &&
2065                         li[2] == fn) {
2066                         unloadListeners.splice(i, 1);
2067                         return true;
2068                     }
2069                 }
2070
2071                 return false;
2072             }
2073
2074             var cacheItem = null;
2075
2076
2077             var index = arguments[3];
2078
2079             if ("undefined" == typeof index) {
2080                 index = this._getCacheIndex(el, eventName, fn);
2081             }
2082
2083             if (index >= 0) {
2084                 cacheItem = listeners[index];
2085             }
2086
2087             if (!el || !cacheItem) {
2088                 return false;
2089             }
2090
2091             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2092
2093             delete listeners[index][this.WFN];
2094             delete listeners[index][this.FN];
2095             listeners.splice(index, 1);
2096
2097             return true;
2098
2099         },
2100
2101
2102         getTarget: function(ev, resolveTextNode) {
2103             ev = ev.browserEvent || ev;
2104             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2105             var t = ev.target || ev.srcElement;
2106             return this.resolveTextNode(t);
2107         },
2108
2109
2110         resolveTextNode: function(node) {
2111             if (Roo.isSafari && node && 3 == node.nodeType) {
2112                 return node.parentNode;
2113             } else {
2114                 return node;
2115             }
2116         },
2117
2118
2119         getPageX: function(ev) {
2120             ev = ev.browserEvent || ev;
2121             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2122             var x = ev.pageX;
2123             if (!x && 0 !== x) {
2124                 x = ev.clientX || 0;
2125
2126                 if (Roo.isIE) {
2127                     x += this.getScroll()[1];
2128                 }
2129             }
2130
2131             return x;
2132         },
2133
2134
2135         getPageY: function(ev) {
2136             ev = ev.browserEvent || ev;
2137             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2138             var y = ev.pageY;
2139             if (!y && 0 !== y) {
2140                 y = ev.clientY || 0;
2141
2142                 if (Roo.isIE) {
2143                     y += this.getScroll()[0];
2144                 }
2145             }
2146
2147
2148             return y;
2149         },
2150
2151
2152         getXY: function(ev) {
2153             ev = ev.browserEvent || ev;
2154             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2155             return [this.getPageX(ev), this.getPageY(ev)];
2156         },
2157
2158
2159         getRelatedTarget: function(ev) {
2160             ev = ev.browserEvent || ev;
2161             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2162             var t = ev.relatedTarget;
2163             if (!t) {
2164                 if (ev.type == "mouseout") {
2165                     t = ev.toElement;
2166                 } else if (ev.type == "mouseover") {
2167                     t = ev.fromElement;
2168                 }
2169             }
2170
2171             return this.resolveTextNode(t);
2172         },
2173
2174
2175         getTime: function(ev) {
2176             ev = ev.browserEvent || ev;
2177             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2178             if (!ev.time) {
2179                 var t = new Date().getTime();
2180                 try {
2181                     ev.time = t;
2182                 } catch(ex) {
2183                     this.lastError = ex;
2184                     return t;
2185                 }
2186             }
2187
2188             return ev.time;
2189         },
2190
2191
2192         stopEvent: function(ev) {
2193             this.stopPropagation(ev);
2194             this.preventDefault(ev);
2195         },
2196
2197
2198         stopPropagation: function(ev) {
2199             ev = ev.browserEvent || ev;
2200             if (ev.stopPropagation) {
2201                 ev.stopPropagation();
2202             } else {
2203                 ev.cancelBubble = true;
2204             }
2205         },
2206
2207
2208         preventDefault: function(ev) {
2209             ev = ev.browserEvent || ev;
2210             if(ev.preventDefault) {
2211                 ev.preventDefault();
2212             } else {
2213                 ev.returnValue = false;
2214             }
2215         },
2216
2217
2218         getEvent: function(e) {
2219             var ev = e || window.event;
2220             if (!ev) {
2221                 var c = this.getEvent.caller;
2222                 while (c) {
2223                     ev = c.arguments[0];
2224                     if (ev && Event == ev.constructor) {
2225                         break;
2226                     }
2227                     c = c.caller;
2228                 }
2229             }
2230             return ev;
2231         },
2232
2233
2234         getCharCode: function(ev) {
2235             ev = ev.browserEvent || ev;
2236             return ev.charCode || ev.keyCode || 0;
2237         },
2238
2239
2240         _getCacheIndex: function(el, eventName, fn) {
2241             for (var i = 0,len = listeners.length; i < len; ++i) {
2242                 var li = listeners[i];
2243                 if (li &&
2244                     li[this.FN] == fn &&
2245                     li[this.EL] == el &&
2246                     li[this.TYPE] == eventName) {
2247                     return i;
2248                 }
2249             }
2250
2251             return -1;
2252         },
2253
2254
2255         elCache: {},
2256
2257
2258         getEl: function(id) {
2259             return document.getElementById(id);
2260         },
2261
2262
2263         clearCache: function() {
2264         },
2265
2266
2267         _load: function(e) {
2268             loadComplete = true;
2269             var EU = Roo.lib.Event;
2270
2271
2272             if (Roo.isIE) {
2273                 EU.doRemove(window, "load", EU._load);
2274             }
2275         },
2276
2277
2278         _tryPreloadAttach: function() {
2279
2280             if (this.locked) {
2281                 return false;
2282             }
2283
2284             this.locked = true;
2285
2286
2287             var tryAgain = !loadComplete;
2288             if (!tryAgain) {
2289                 tryAgain = (retryCount > 0);
2290             }
2291
2292
2293             var notAvail = [];
2294             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2295                 var item = onAvailStack[i];
2296                 if (item) {
2297                     var el = this.getEl(item.id);
2298
2299                     if (el) {
2300                         if (!item.checkReady ||
2301                             loadComplete ||
2302                             el.nextSibling ||
2303                             (document && document.body)) {
2304
2305                             var scope = el;
2306                             if (item.override) {
2307                                 if (item.override === true) {
2308                                     scope = item.obj;
2309                                 } else {
2310                                     scope = item.override;
2311                                 }
2312                             }
2313                             item.fn.call(scope, item.obj);
2314                             onAvailStack[i] = null;
2315                         }
2316                     } else {
2317                         notAvail.push(item);
2318                     }
2319                 }
2320             }
2321
2322             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323
2324             if (tryAgain) {
2325
2326                 this.startInterval();
2327             } else {
2328                 clearInterval(this._interval);
2329                 this._interval = null;
2330             }
2331
2332             this.locked = false;
2333
2334             return true;
2335
2336         },
2337
2338
2339         purgeElement: function(el, recurse, eventName) {
2340             var elListeners = this.getListeners(el, eventName);
2341             if (elListeners) {
2342                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2343                     var l = elListeners[i];
2344                     this.removeListener(el, l.type, l.fn);
2345                 }
2346             }
2347
2348             if (recurse && el && el.childNodes) {
2349                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2350                     this.purgeElement(el.childNodes[i], recurse, eventName);
2351                 }
2352             }
2353         },
2354
2355
2356         getListeners: function(el, eventName) {
2357             var results = [], searchLists;
2358             if (!eventName) {
2359                 searchLists = [listeners, unloadListeners];
2360             } else if (eventName == "unload") {
2361                 searchLists = [unloadListeners];
2362             } else {
2363                 searchLists = [listeners];
2364             }
2365
2366             for (var j = 0; j < searchLists.length; ++j) {
2367                 var searchList = searchLists[j];
2368                 if (searchList && searchList.length > 0) {
2369                     for (var i = 0,len = searchList.length; i < len; ++i) {
2370                         var l = searchList[i];
2371                         if (l && l[this.EL] === el &&
2372                             (!eventName || eventName === l[this.TYPE])) {
2373                             results.push({
2374                                 type:   l[this.TYPE],
2375                                 fn:     l[this.FN],
2376                                 obj:    l[this.OBJ],
2377                                 adjust: l[this.ADJ_SCOPE],
2378                                 index:  i
2379                             });
2380                         }
2381                     }
2382                 }
2383             }
2384
2385             return (results.length) ? results : null;
2386         },
2387
2388
2389         _unload: function(e) {
2390
2391             var EU = Roo.lib.Event, i, j, l, len, index;
2392
2393             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2394                 l = unloadListeners[i];
2395                 if (l) {
2396                     var scope = window;
2397                     if (l[EU.ADJ_SCOPE]) {
2398                         if (l[EU.ADJ_SCOPE] === true) {
2399                             scope = l[EU.OBJ];
2400                         } else {
2401                             scope = l[EU.ADJ_SCOPE];
2402                         }
2403                     }
2404                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2405                     unloadListeners[i] = null;
2406                     l = null;
2407                     scope = null;
2408                 }
2409             }
2410
2411             unloadListeners = null;
2412
2413             if (listeners && listeners.length > 0) {
2414                 j = listeners.length;
2415                 while (j) {
2416                     index = j - 1;
2417                     l = listeners[index];
2418                     if (l) {
2419                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2420                                 l[EU.FN], index);
2421                     }
2422                     j = j - 1;
2423                 }
2424                 l = null;
2425
2426                 EU.clearCache();
2427             }
2428
2429             EU.doRemove(window, "unload", EU._unload);
2430
2431         },
2432
2433
2434         getScroll: function() {
2435             var dd = document.documentElement, db = document.body;
2436             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2437                 return [dd.scrollTop, dd.scrollLeft];
2438             } else if (db) {
2439                 return [db.scrollTop, db.scrollLeft];
2440             } else {
2441                 return [0, 0];
2442             }
2443         },
2444
2445
2446         doAdd: function () {
2447             if (window.addEventListener) {
2448                 return function(el, eventName, fn, capture) {
2449                     el.addEventListener(eventName, fn, (capture));
2450                 };
2451             } else if (window.attachEvent) {
2452                 return function(el, eventName, fn, capture) {
2453                     el.attachEvent("on" + eventName, fn);
2454                 };
2455             } else {
2456                 return function() {
2457                 };
2458             }
2459         }(),
2460
2461
2462         doRemove: function() {
2463             if (window.removeEventListener) {
2464                 return function (el, eventName, fn, capture) {
2465                     el.removeEventListener(eventName, fn, (capture));
2466                 };
2467             } else if (window.detachEvent) {
2468                 return function (el, eventName, fn) {
2469                     el.detachEvent("on" + eventName, fn);
2470                 };
2471             } else {
2472                 return function() {
2473                 };
2474             }
2475         }()
2476     };
2477     
2478 }();
2479 (function() {     
2480    
2481     var E = Roo.lib.Event;
2482     E.on = E.addListener;
2483     E.un = E.removeListener;
2484
2485     if (document && document.body) {
2486         E._load();
2487     } else {
2488         E.doAdd(window, "load", E._load);
2489     }
2490     E.doAdd(window, "unload", E._unload);
2491     E._tryPreloadAttach();
2492 })();
2493
2494 /*
2495  * Portions of this file are based on pieces of Yahoo User Interface Library
2496  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2497  * YUI licensed under the BSD License:
2498  * http://developer.yahoo.net/yui/license.txt
2499  * <script type="text/javascript">
2500  *
2501  */
2502
2503 (function() {
2504     /**
2505      * @class Roo.lib.Ajax
2506      *
2507      */
2508     Roo.lib.Ajax = {
2509         /**
2510          * @static 
2511          */
2512         request : function(method, uri, cb, data, options) {
2513             if(options){
2514                 var hs = options.headers;
2515                 if(hs){
2516                     for(var h in hs){
2517                         if(hs.hasOwnProperty(h)){
2518                             this.initHeader(h, hs[h], false);
2519                         }
2520                     }
2521                 }
2522                 if(options.xmlData){
2523                     this.initHeader('Content-Type', 'text/xml', false);
2524                     method = 'POST';
2525                     data = options.xmlData;
2526                 }
2527             }
2528
2529             return this.asyncRequest(method, uri, cb, data);
2530         },
2531
2532         serializeForm : function(form) {
2533             if(typeof form == 'string') {
2534                 form = (document.getElementById(form) || document.forms[form]);
2535             }
2536
2537             var el, name, val, disabled, data = '', hasSubmit = false;
2538             for (var i = 0; i < form.elements.length; i++) {
2539                 el = form.elements[i];
2540                 disabled = form.elements[i].disabled;
2541                 name = form.elements[i].name;
2542                 val = form.elements[i].value;
2543
2544                 if (!disabled && name){
2545                     switch (el.type)
2546                             {
2547                         case 'select-one':
2548                         case 'select-multiple':
2549                             for (var j = 0; j < el.options.length; j++) {
2550                                 if (el.options[j].selected) {
2551                                     if (Roo.isIE) {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                     else {
2555                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2556                                     }
2557                                 }
2558                             }
2559                             break;
2560                         case 'radio':
2561                         case 'checkbox':
2562                             if (el.checked) {
2563                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2564                             }
2565                             break;
2566                         case 'file':
2567
2568                         case undefined:
2569
2570                         case 'reset':
2571
2572                         case 'button':
2573
2574                             break;
2575                         case 'submit':
2576                             if(hasSubmit == false) {
2577                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2578                                 hasSubmit = true;
2579                             }
2580                             break;
2581                         default:
2582                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2583                             break;
2584                     }
2585                 }
2586             }
2587             data = data.substr(0, data.length - 1);
2588             return data;
2589         },
2590
2591         headers:{},
2592
2593         hasHeaders:false,
2594
2595         useDefaultHeader:true,
2596
2597         defaultPostHeader:'application/x-www-form-urlencoded',
2598
2599         useDefaultXhrHeader:true,
2600
2601         defaultXhrHeader:'XMLHttpRequest',
2602
2603         hasDefaultHeaders:true,
2604
2605         defaultHeaders:{},
2606
2607         poll:{},
2608
2609         timeout:{},
2610
2611         pollInterval:50,
2612
2613         transactionId:0,
2614
2615         setProgId:function(id)
2616         {
2617             this.activeX.unshift(id);
2618         },
2619
2620         setDefaultPostHeader:function(b)
2621         {
2622             this.useDefaultHeader = b;
2623         },
2624
2625         setDefaultXhrHeader:function(b)
2626         {
2627             this.useDefaultXhrHeader = b;
2628         },
2629
2630         setPollingInterval:function(i)
2631         {
2632             if (typeof i == 'number' && isFinite(i)) {
2633                 this.pollInterval = i;
2634             }
2635         },
2636
2637         createXhrObject:function(transactionId)
2638         {
2639             var obj,http;
2640             try
2641             {
2642
2643                 http = new XMLHttpRequest();
2644
2645                 obj = { conn:http, tId:transactionId };
2646             }
2647             catch(e)
2648             {
2649                 for (var i = 0; i < this.activeX.length; ++i) {
2650                     try
2651                     {
2652
2653                         http = new ActiveXObject(this.activeX[i]);
2654
2655                         obj = { conn:http, tId:transactionId };
2656                         break;
2657                     }
2658                     catch(e) {
2659                     }
2660                 }
2661             }
2662             finally
2663             {
2664                 return obj;
2665             }
2666         },
2667
2668         getConnectionObject:function()
2669         {
2670             var o;
2671             var tId = this.transactionId;
2672
2673             try
2674             {
2675                 o = this.createXhrObject(tId);
2676                 if (o) {
2677                     this.transactionId++;
2678                 }
2679             }
2680             catch(e) {
2681             }
2682             finally
2683             {
2684                 return o;
2685             }
2686         },
2687
2688         asyncRequest:function(method, uri, callback, postData)
2689         {
2690             var o = this.getConnectionObject();
2691
2692             if (!o) {
2693                 return null;
2694             }
2695             else {
2696                 o.conn.open(method, uri, true);
2697
2698                 if (this.useDefaultXhrHeader) {
2699                     if (!this.defaultHeaders['X-Requested-With']) {
2700                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701                     }
2702                 }
2703
2704                 if(postData && this.useDefaultHeader){
2705                     this.initHeader('Content-Type', this.defaultPostHeader);
2706                 }
2707
2708                  if (this.hasDefaultHeaders || this.hasHeaders) {
2709                     this.setHeader(o);
2710                 }
2711
2712                 this.handleReadyState(o, callback);
2713                 o.conn.send(postData || null);
2714
2715                 return o;
2716             }
2717         },
2718
2719         handleReadyState:function(o, callback)
2720         {
2721             var oConn = this;
2722
2723             if (callback && callback.timeout) {
2724                 
2725                 this.timeout[o.tId] = window.setTimeout(function() {
2726                     oConn.abort(o, callback, true);
2727                 }, callback.timeout);
2728             }
2729
2730             this.poll[o.tId] = window.setInterval(
2731                     function() {
2732                         if (o.conn && o.conn.readyState == 4) {
2733                             window.clearInterval(oConn.poll[o.tId]);
2734                             delete oConn.poll[o.tId];
2735
2736                             if(callback && callback.timeout) {
2737                                 window.clearTimeout(oConn.timeout[o.tId]);
2738                                 delete oConn.timeout[o.tId];
2739                             }
2740
2741                             oConn.handleTransactionResponse(o, callback);
2742                         }
2743                     }
2744                     , this.pollInterval);
2745         },
2746
2747         handleTransactionResponse:function(o, callback, isAbort)
2748         {
2749
2750             if (!callback) {
2751                 this.releaseObject(o);
2752                 return;
2753             }
2754
2755             var httpStatus, responseObject;
2756
2757             try
2758             {
2759                 if (o.conn.status !== undefined && o.conn.status != 0) {
2760                     httpStatus = o.conn.status;
2761                 }
2762                 else {
2763                     httpStatus = 13030;
2764                 }
2765             }
2766             catch(e) {
2767
2768
2769                 httpStatus = 13030;
2770             }
2771
2772             if (httpStatus >= 200 && httpStatus < 300) {
2773                 responseObject = this.createResponseObject(o, callback.argument);
2774                 if (callback.success) {
2775                     if (!callback.scope) {
2776                         callback.success(responseObject);
2777                     }
2778                     else {
2779
2780
2781                         callback.success.apply(callback.scope, [responseObject]);
2782                     }
2783                 }
2784             }
2785             else {
2786                 switch (httpStatus) {
2787
2788                     case 12002:
2789                     case 12029:
2790                     case 12030:
2791                     case 12031:
2792                     case 12152:
2793                     case 13030:
2794                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2795                         if (callback.failure) {
2796                             if (!callback.scope) {
2797                                 callback.failure(responseObject);
2798                             }
2799                             else {
2800                                 callback.failure.apply(callback.scope, [responseObject]);
2801                             }
2802                         }
2803                         break;
2804                     default:
2805                         responseObject = this.createResponseObject(o, callback.argument);
2806                         if (callback.failure) {
2807                             if (!callback.scope) {
2808                                 callback.failure(responseObject);
2809                             }
2810                             else {
2811                                 callback.failure.apply(callback.scope, [responseObject]);
2812                             }
2813                         }
2814                 }
2815             }
2816
2817             this.releaseObject(o);
2818             responseObject = null;
2819         },
2820
2821         createResponseObject:function(o, callbackArg)
2822         {
2823             var obj = {};
2824             var headerObj = {};
2825
2826             try
2827             {
2828                 var headerStr = o.conn.getAllResponseHeaders();
2829                 var header = headerStr.split('\n');
2830                 for (var i = 0; i < header.length; i++) {
2831                     var delimitPos = header[i].indexOf(':');
2832                     if (delimitPos != -1) {
2833                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2834                     }
2835                 }
2836             }
2837             catch(e) {
2838             }
2839
2840             obj.tId = o.tId;
2841             obj.status = o.conn.status;
2842             obj.statusText = o.conn.statusText;
2843             obj.getResponseHeader = headerObj;
2844             obj.getAllResponseHeaders = headerStr;
2845             obj.responseText = o.conn.responseText;
2846             obj.responseXML = o.conn.responseXML;
2847
2848             if (typeof callbackArg !== undefined) {
2849                 obj.argument = callbackArg;
2850             }
2851
2852             return obj;
2853         },
2854
2855         createExceptionObject:function(tId, callbackArg, isAbort)
2856         {
2857             var COMM_CODE = 0;
2858             var COMM_ERROR = 'communication failure';
2859             var ABORT_CODE = -1;
2860             var ABORT_ERROR = 'transaction aborted';
2861
2862             var obj = {};
2863
2864             obj.tId = tId;
2865             if (isAbort) {
2866                 obj.status = ABORT_CODE;
2867                 obj.statusText = ABORT_ERROR;
2868             }
2869             else {
2870                 obj.status = COMM_CODE;
2871                 obj.statusText = COMM_ERROR;
2872             }
2873
2874             if (callbackArg) {
2875                 obj.argument = callbackArg;
2876             }
2877
2878             return obj;
2879         },
2880
2881         initHeader:function(label, value, isDefault)
2882         {
2883             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2884
2885             if (headerObj[label] === undefined) {
2886                 headerObj[label] = value;
2887             }
2888             else {
2889
2890
2891                 headerObj[label] = value + "," + headerObj[label];
2892             }
2893
2894             if (isDefault) {
2895                 this.hasDefaultHeaders = true;
2896             }
2897             else {
2898                 this.hasHeaders = true;
2899             }
2900         },
2901
2902
2903         setHeader:function(o)
2904         {
2905             if (this.hasDefaultHeaders) {
2906                 for (var prop in this.defaultHeaders) {
2907                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2908                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2909                     }
2910                 }
2911             }
2912
2913             if (this.hasHeaders) {
2914                 for (var prop in this.headers) {
2915                     if (this.headers.hasOwnProperty(prop)) {
2916                         o.conn.setRequestHeader(prop, this.headers[prop]);
2917                     }
2918                 }
2919                 this.headers = {};
2920                 this.hasHeaders = false;
2921             }
2922         },
2923
2924         resetDefaultHeaders:function() {
2925             delete this.defaultHeaders;
2926             this.defaultHeaders = {};
2927             this.hasDefaultHeaders = false;
2928         },
2929
2930         abort:function(o, callback, isTimeout)
2931         {
2932             if(this.isCallInProgress(o)) {
2933                 o.conn.abort();
2934                 window.clearInterval(this.poll[o.tId]);
2935                 delete this.poll[o.tId];
2936                 if (isTimeout) {
2937                     delete this.timeout[o.tId];
2938                 }
2939
2940                 this.handleTransactionResponse(o, callback, true);
2941
2942                 return true;
2943             }
2944             else {
2945                 return false;
2946             }
2947         },
2948
2949
2950         isCallInProgress:function(o)
2951         {
2952             if (o && o.conn) {
2953                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2954             }
2955             else {
2956
2957                 return false;
2958             }
2959         },
2960
2961
2962         releaseObject:function(o)
2963         {
2964
2965             o.conn = null;
2966
2967             o = null;
2968         },
2969
2970         activeX:[
2971         'MSXML2.XMLHTTP.3.0',
2972         'MSXML2.XMLHTTP',
2973         'Microsoft.XMLHTTP'
2974         ]
2975
2976
2977     };
2978 })();/*
2979  * Portions of this file are based on pieces of Yahoo User Interface Library
2980  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2981  * YUI licensed under the BSD License:
2982  * http://developer.yahoo.net/yui/license.txt
2983  * <script type="text/javascript">
2984  *
2985  */
2986
2987 Roo.lib.Region = function(t, r, b, l) {
2988     this.top = t;
2989     this[1] = t;
2990     this.right = r;
2991     this.bottom = b;
2992     this.left = l;
2993     this[0] = l;
2994 };
2995
2996
2997 Roo.lib.Region.prototype = {
2998     contains : function(region) {
2999         return ( region.left >= this.left &&
3000                  region.right <= this.right &&
3001                  region.top >= this.top &&
3002                  region.bottom <= this.bottom    );
3003
3004     },
3005
3006     getArea : function() {
3007         return ( (this.bottom - this.top) * (this.right - this.left) );
3008     },
3009
3010     intersect : function(region) {
3011         var t = Math.max(this.top, region.top);
3012         var r = Math.min(this.right, region.right);
3013         var b = Math.min(this.bottom, region.bottom);
3014         var l = Math.max(this.left, region.left);
3015
3016         if (b >= t && r >= l) {
3017             return new Roo.lib.Region(t, r, b, l);
3018         } else {
3019             return null;
3020         }
3021     },
3022     union : function(region) {
3023         var t = Math.min(this.top, region.top);
3024         var r = Math.max(this.right, region.right);
3025         var b = Math.max(this.bottom, region.bottom);
3026         var l = Math.min(this.left, region.left);
3027
3028         return new Roo.lib.Region(t, r, b, l);
3029     },
3030
3031     adjust : function(t, l, b, r) {
3032         this.top += t;
3033         this.left += l;
3034         this.right += r;
3035         this.bottom += b;
3036         return this;
3037     }
3038 };
3039
3040 Roo.lib.Region.getRegion = function(el) {
3041     var p = Roo.lib.Dom.getXY(el);
3042
3043     var t = p[1];
3044     var r = p[0] + el.offsetWidth;
3045     var b = p[1] + el.offsetHeight;
3046     var l = p[0];
3047
3048     return new Roo.lib.Region(t, r, b, l);
3049 };
3050 /*
3051  * Portions of this file are based on pieces of Yahoo User Interface Library
3052  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3053  * YUI licensed under the BSD License:
3054  * http://developer.yahoo.net/yui/license.txt
3055  * <script type="text/javascript">
3056  *
3057  */
3058 //@@dep Roo.lib.Region
3059
3060
3061 Roo.lib.Point = function(x, y) {
3062     if (x instanceof Array) {
3063         y = x[1];
3064         x = x[0];
3065     }
3066     this.x = this.right = this.left = this[0] = x;
3067     this.y = this.top = this.bottom = this[1] = y;
3068 };
3069
3070 Roo.lib.Point.prototype = new Roo.lib.Region();
3071 /*
3072  * Portions of this file are based on pieces of Yahoo User Interface Library
3073  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3074  * YUI licensed under the BSD License:
3075  * http://developer.yahoo.net/yui/license.txt
3076  * <script type="text/javascript">
3077  *
3078  */
3079  
3080 (function() {   
3081
3082     Roo.lib.Anim = {
3083         scroll : function(el, args, duration, easing, cb, scope) {
3084             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3085         },
3086
3087         motion : function(el, args, duration, easing, cb, scope) {
3088             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3089         },
3090
3091         color : function(el, args, duration, easing, cb, scope) {
3092             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3093         },
3094
3095         run : function(el, args, duration, easing, cb, scope, type) {
3096             type = type || Roo.lib.AnimBase;
3097             if (typeof easing == "string") {
3098                 easing = Roo.lib.Easing[easing];
3099             }
3100             var anim = new type(el, args, duration, easing);
3101             anim.animateX(function() {
3102                 Roo.callback(cb, scope);
3103             });
3104             return anim;
3105         }
3106     };
3107 })();/*
3108  * Portions of this file are based on pieces of Yahoo User Interface Library
3109  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3110  * YUI licensed under the BSD License:
3111  * http://developer.yahoo.net/yui/license.txt
3112  * <script type="text/javascript">
3113  *
3114  */
3115
3116 (function() {    
3117     var libFlyweight;
3118     
3119     function fly(el) {
3120         if (!libFlyweight) {
3121             libFlyweight = new Roo.Element.Flyweight();
3122         }
3123         libFlyweight.dom = el;
3124         return libFlyweight;
3125     }
3126
3127     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128     
3129    
3130     
3131     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3132         if (el) {
3133             this.init(el, attributes, duration, method);
3134         }
3135     };
3136
3137     Roo.lib.AnimBase.fly = fly;
3138     
3139     
3140     
3141     Roo.lib.AnimBase.prototype = {
3142
3143         toString: function() {
3144             var el = this.getEl();
3145             var id = el.id || el.tagName;
3146             return ("Anim " + id);
3147         },
3148
3149         patterns: {
3150             noNegatives:        /width|height|opacity|padding/i,
3151             offsetAttribute:  /^((width|height)|(top|left))$/,
3152             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3153             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154         },
3155
3156
3157         doMethod: function(attr, start, end) {
3158             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159         },
3160
3161
3162         setAttribute: function(attr, val, unit) {
3163             if (this.patterns.noNegatives.test(attr)) {
3164                 val = (val > 0) ? val : 0;
3165             }
3166
3167             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168         },
3169
3170
3171         getAttribute: function(attr) {
3172             var el = this.getEl();
3173             var val = fly(el).getStyle(attr);
3174
3175             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3176                 return parseFloat(val);
3177             }
3178
3179             var a = this.patterns.offsetAttribute.exec(attr) || [];
3180             var pos = !!( a[3] );
3181             var box = !!( a[2] );
3182
3183
3184             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3185                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3186             } else {
3187                 val = 0;
3188             }
3189
3190             return val;
3191         },
3192
3193
3194         getDefaultUnit: function(attr) {
3195             if (this.patterns.defaultUnit.test(attr)) {
3196                 return 'px';
3197             }
3198
3199             return '';
3200         },
3201
3202         animateX : function(callback, scope) {
3203             var f = function() {
3204                 this.onComplete.removeListener(f);
3205                 if (typeof callback == "function") {
3206                     callback.call(scope || this, this);
3207                 }
3208             };
3209             this.onComplete.addListener(f, this);
3210             this.animate();
3211         },
3212
3213
3214         setRuntimeAttribute: function(attr) {
3215             var start;
3216             var end;
3217             var attributes = this.attributes;
3218
3219             this.runtimeAttributes[attr] = {};
3220
3221             var isset = function(prop) {
3222                 return (typeof prop !== 'undefined');
3223             };
3224
3225             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226                 return false;
3227             }
3228
3229             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3230
3231
3232             if (isset(attributes[attr]['to'])) {
3233                 end = attributes[attr]['to'];
3234             } else if (isset(attributes[attr]['by'])) {
3235                 if (start.constructor == Array) {
3236                     end = [];
3237                     for (var i = 0, len = start.length; i < len; ++i) {
3238                         end[i] = start[i] + attributes[attr]['by'][i];
3239                     }
3240                 } else {
3241                     end = start + attributes[attr]['by'];
3242                 }
3243             }
3244
3245             this.runtimeAttributes[attr].start = start;
3246             this.runtimeAttributes[attr].end = end;
3247
3248
3249             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250         },
3251
3252
3253         init: function(el, attributes, duration, method) {
3254
3255             var isAnimated = false;
3256
3257
3258             var startTime = null;
3259
3260
3261             var actualFrames = 0;
3262
3263
3264             el = Roo.getDom(el);
3265
3266
3267             this.attributes = attributes || {};
3268
3269
3270             this.duration = duration || 1;
3271
3272
3273             this.method = method || Roo.lib.Easing.easeNone;
3274
3275
3276             this.useSeconds = true;
3277
3278
3279             this.currentFrame = 0;
3280
3281
3282             this.totalFrames = Roo.lib.AnimMgr.fps;
3283
3284
3285             this.getEl = function() {
3286                 return el;
3287             };
3288
3289
3290             this.isAnimated = function() {
3291                 return isAnimated;
3292             };
3293
3294
3295             this.getStartTime = function() {
3296                 return startTime;
3297             };
3298
3299             this.runtimeAttributes = {};
3300
3301
3302             this.animate = function() {
3303                 if (this.isAnimated()) {
3304                     return false;
3305                 }
3306
3307                 this.currentFrame = 0;
3308
3309                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3310
3311                 Roo.lib.AnimMgr.registerElement(this);
3312             };
3313
3314
3315             this.stop = function(finish) {
3316                 if (finish) {
3317                     this.currentFrame = this.totalFrames;
3318                     this._onTween.fire();
3319                 }
3320                 Roo.lib.AnimMgr.stop(this);
3321             };
3322
3323             var onStart = function() {
3324                 this.onStart.fire();
3325
3326                 this.runtimeAttributes = {};
3327                 for (var attr in this.attributes) {
3328                     this.setRuntimeAttribute(attr);
3329                 }
3330
3331                 isAnimated = true;
3332                 actualFrames = 0;
3333                 startTime = new Date();
3334             };
3335
3336
3337             var onTween = function() {
3338                 var data = {
3339                     duration: new Date() - this.getStartTime(),
3340                     currentFrame: this.currentFrame
3341                 };
3342
3343                 data.toString = function() {
3344                     return (
3345                             'duration: ' + data.duration +
3346                             ', currentFrame: ' + data.currentFrame
3347                             );
3348                 };
3349
3350                 this.onTween.fire(data);
3351
3352                 var runtimeAttributes = this.runtimeAttributes;
3353
3354                 for (var attr in runtimeAttributes) {
3355                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3356                 }
3357
3358                 actualFrames += 1;
3359             };
3360
3361             var onComplete = function() {
3362                 var actual_duration = (new Date() - startTime) / 1000 ;
3363
3364                 var data = {
3365                     duration: actual_duration,
3366                     frames: actualFrames,
3367                     fps: actualFrames / actual_duration
3368                 };
3369
3370                 data.toString = function() {
3371                     return (
3372                             'duration: ' + data.duration +
3373                             ', frames: ' + data.frames +
3374                             ', fps: ' + data.fps
3375                             );
3376                 };
3377
3378                 isAnimated = false;
3379                 actualFrames = 0;
3380                 this.onComplete.fire(data);
3381             };
3382
3383
3384             this._onStart = new Roo.util.Event(this);
3385             this.onStart = new Roo.util.Event(this);
3386             this.onTween = new Roo.util.Event(this);
3387             this._onTween = new Roo.util.Event(this);
3388             this.onComplete = new Roo.util.Event(this);
3389             this._onComplete = new Roo.util.Event(this);
3390             this._onStart.addListener(onStart);
3391             this._onTween.addListener(onTween);
3392             this._onComplete.addListener(onComplete);
3393         }
3394     };
3395 })();
3396 /*
3397  * Portions of this file are based on pieces of Yahoo User Interface Library
3398  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3399  * YUI licensed under the BSD License:
3400  * http://developer.yahoo.net/yui/license.txt
3401  * <script type="text/javascript">
3402  *
3403  */
3404
3405 Roo.lib.AnimMgr = new function() {
3406
3407     var thread = null;
3408
3409
3410     var queue = [];
3411
3412
3413     var tweenCount = 0;
3414
3415
3416     this.fps = 1000;
3417
3418
3419     this.delay = 1;
3420
3421
3422     this.registerElement = function(tween) {
3423         queue[queue.length] = tween;
3424         tweenCount += 1;
3425         tween._onStart.fire();
3426         this.start();
3427     };
3428
3429
3430     this.unRegister = function(tween, index) {
3431         tween._onComplete.fire();
3432         index = index || getIndex(tween);
3433         if (index != -1) {
3434             queue.splice(index, 1);
3435         }
3436
3437         tweenCount -= 1;
3438         if (tweenCount <= 0) {
3439             this.stop();
3440         }
3441     };
3442
3443
3444     this.start = function() {
3445         if (thread === null) {
3446             thread = setInterval(this.run, this.delay);
3447         }
3448     };
3449
3450
3451     this.stop = function(tween) {
3452         if (!tween) {
3453             clearInterval(thread);
3454
3455             for (var i = 0, len = queue.length; i < len; ++i) {
3456                 if (queue[0].isAnimated()) {
3457                     this.unRegister(queue[0], 0);
3458                 }
3459             }
3460
3461             queue = [];
3462             thread = null;
3463             tweenCount = 0;
3464         }
3465         else {
3466             this.unRegister(tween);
3467         }
3468     };
3469
3470
3471     this.run = function() {
3472         for (var i = 0, len = queue.length; i < len; ++i) {
3473             var tween = queue[i];
3474             if (!tween || !tween.isAnimated()) {
3475                 continue;
3476             }
3477
3478             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3479             {
3480                 tween.currentFrame += 1;
3481
3482                 if (tween.useSeconds) {
3483                     correctFrame(tween);
3484                 }
3485                 tween._onTween.fire();
3486             }
3487             else {
3488                 Roo.lib.AnimMgr.stop(tween, i);
3489             }
3490         }
3491     };
3492
3493     var getIndex = function(anim) {
3494         for (var i = 0, len = queue.length; i < len; ++i) {
3495             if (queue[i] == anim) {
3496                 return i;
3497             }
3498         }
3499         return -1;
3500     };
3501
3502
3503     var correctFrame = function(tween) {
3504         var frames = tween.totalFrames;
3505         var frame = tween.currentFrame;
3506         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3507         var elapsed = (new Date() - tween.getStartTime());
3508         var tweak = 0;
3509
3510         if (elapsed < tween.duration * 1000) {
3511             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3512         } else {
3513             tweak = frames - (frame + 1);
3514         }
3515         if (tweak > 0 && isFinite(tweak)) {
3516             if (tween.currentFrame + tweak >= frames) {
3517                 tweak = frames - (frame + 1);
3518             }
3519
3520             tween.currentFrame += tweak;
3521         }
3522     };
3523 };
3524
3525     /*
3526  * Portions of this file are based on pieces of Yahoo User Interface Library
3527  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3528  * YUI licensed under the BSD License:
3529  * http://developer.yahoo.net/yui/license.txt
3530  * <script type="text/javascript">
3531  *
3532  */
3533 Roo.lib.Bezier = new function() {
3534
3535         this.getPosition = function(points, t) {
3536             var n = points.length;
3537             var tmp = [];
3538
3539             for (var i = 0; i < n; ++i) {
3540                 tmp[i] = [points[i][0], points[i][1]];
3541             }
3542
3543             for (var j = 1; j < n; ++j) {
3544                 for (i = 0; i < n - j; ++i) {
3545                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3546                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547                 }
3548             }
3549
3550             return [ tmp[0][0], tmp[0][1] ];
3551
3552         };
3553     };/*
3554  * Portions of this file are based on pieces of Yahoo User Interface Library
3555  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3556  * YUI licensed under the BSD License:
3557  * http://developer.yahoo.net/yui/license.txt
3558  * <script type="text/javascript">
3559  *
3560  */
3561 (function() {
3562
3563     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3564         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3565     };
3566
3567     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3568
3569     var fly = Roo.lib.AnimBase.fly;
3570     var Y = Roo.lib;
3571     var superclass = Y.ColorAnim.superclass;
3572     var proto = Y.ColorAnim.prototype;
3573
3574     proto.toString = function() {
3575         var el = this.getEl();
3576         var id = el.id || el.tagName;
3577         return ("ColorAnim " + id);
3578     };
3579
3580     proto.patterns.color = /color$/i;
3581     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3582     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3583     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3584     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3585
3586
3587     proto.parseColor = function(s) {
3588         if (s.length == 3) {
3589             return s;
3590         }
3591
3592         var c = this.patterns.hex.exec(s);
3593         if (c && c.length == 4) {
3594             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3595         }
3596
3597         c = this.patterns.rgb.exec(s);
3598         if (c && c.length == 4) {
3599             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3600         }
3601
3602         c = this.patterns.hex3.exec(s);
3603         if (c && c.length == 4) {
3604             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3605         }
3606
3607         return null;
3608     };
3609     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3610     proto.getAttribute = function(attr) {
3611         var el = this.getEl();
3612         if (this.patterns.color.test(attr)) {
3613             var val = fly(el).getStyle(attr);
3614
3615             if (this.patterns.transparent.test(val)) {
3616                 var parent = el.parentNode;
3617                 val = fly(parent).getStyle(attr);
3618
3619                 while (parent && this.patterns.transparent.test(val)) {
3620                     parent = parent.parentNode;
3621                     val = fly(parent).getStyle(attr);
3622                     if (parent.tagName.toUpperCase() == 'HTML') {
3623                         val = '#fff';
3624                     }
3625                 }
3626             }
3627         } else {
3628             val = superclass.getAttribute.call(this, attr);
3629         }
3630
3631         return val;
3632     };
3633     proto.getAttribute = function(attr) {
3634         var el = this.getEl();
3635         if (this.patterns.color.test(attr)) {
3636             var val = fly(el).getStyle(attr);
3637
3638             if (this.patterns.transparent.test(val)) {
3639                 var parent = el.parentNode;
3640                 val = fly(parent).getStyle(attr);
3641
3642                 while (parent && this.patterns.transparent.test(val)) {
3643                     parent = parent.parentNode;
3644                     val = fly(parent).getStyle(attr);
3645                     if (parent.tagName.toUpperCase() == 'HTML') {
3646                         val = '#fff';
3647                     }
3648                 }
3649             }
3650         } else {
3651             val = superclass.getAttribute.call(this, attr);
3652         }
3653
3654         return val;
3655     };
3656
3657     proto.doMethod = function(attr, start, end) {
3658         var val;
3659
3660         if (this.patterns.color.test(attr)) {
3661             val = [];
3662             for (var i = 0, len = start.length; i < len; ++i) {
3663                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3664             }
3665
3666             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3667         }
3668         else {
3669             val = superclass.doMethod.call(this, attr, start, end);
3670         }
3671
3672         return val;
3673     };
3674
3675     proto.setRuntimeAttribute = function(attr) {
3676         superclass.setRuntimeAttribute.call(this, attr);
3677
3678         if (this.patterns.color.test(attr)) {
3679             var attributes = this.attributes;
3680             var start = this.parseColor(this.runtimeAttributes[attr].start);
3681             var end = this.parseColor(this.runtimeAttributes[attr].end);
3682
3683             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3684                 end = this.parseColor(attributes[attr].by);
3685
3686                 for (var i = 0, len = start.length; i < len; ++i) {
3687                     end[i] = start[i] + end[i];
3688                 }
3689             }
3690
3691             this.runtimeAttributes[attr].start = start;
3692             this.runtimeAttributes[attr].end = end;
3693         }
3694     };
3695 })();
3696
3697 /*
3698  * Portions of this file are based on pieces of Yahoo User Interface Library
3699  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3700  * YUI licensed under the BSD License:
3701  * http://developer.yahoo.net/yui/license.txt
3702  * <script type="text/javascript">
3703  *
3704  */
3705 Roo.lib.Easing = {
3706
3707
3708     easeNone: function (t, b, c, d) {
3709         return c * t / d + b;
3710     },
3711
3712
3713     easeIn: function (t, b, c, d) {
3714         return c * (t /= d) * t + b;
3715     },
3716
3717
3718     easeOut: function (t, b, c, d) {
3719         return -c * (t /= d) * (t - 2) + b;
3720     },
3721
3722
3723     easeBoth: function (t, b, c, d) {
3724         if ((t /= d / 2) < 1) {
3725             return c / 2 * t * t + b;
3726         }
3727
3728         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729     },
3730
3731
3732     easeInStrong: function (t, b, c, d) {
3733         return c * (t /= d) * t * t * t + b;
3734     },
3735
3736
3737     easeOutStrong: function (t, b, c, d) {
3738         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739     },
3740
3741
3742     easeBothStrong: function (t, b, c, d) {
3743         if ((t /= d / 2) < 1) {
3744             return c / 2 * t * t * t * t + b;
3745         }
3746
3747         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3748     },
3749
3750
3751
3752     elasticIn: function (t, b, c, d, a, p) {
3753         if (t == 0) {
3754             return b;
3755         }
3756         if ((t /= d) == 1) {
3757             return b + c;
3758         }
3759         if (!p) {
3760             p = d * .3;
3761         }
3762
3763         if (!a || a < Math.abs(c)) {
3764             a = c;
3765             var s = p / 4;
3766         }
3767         else {
3768             var s = p / (2 * Math.PI) * Math.asin(c / a);
3769         }
3770
3771         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772     },
3773
3774
3775     elasticOut: function (t, b, c, d, a, p) {
3776         if (t == 0) {
3777             return b;
3778         }
3779         if ((t /= d) == 1) {
3780             return b + c;
3781         }
3782         if (!p) {
3783             p = d * .3;
3784         }
3785
3786         if (!a || a < Math.abs(c)) {
3787             a = c;
3788             var s = p / 4;
3789         }
3790         else {
3791             var s = p / (2 * Math.PI) * Math.asin(c / a);
3792         }
3793
3794         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795     },
3796
3797
3798     elasticBoth: function (t, b, c, d, a, p) {
3799         if (t == 0) {
3800             return b;
3801         }
3802
3803         if ((t /= d / 2) == 2) {
3804             return b + c;
3805         }
3806
3807         if (!p) {
3808             p = d * (.3 * 1.5);
3809         }
3810
3811         if (!a || a < Math.abs(c)) {
3812             a = c;
3813             var s = p / 4;
3814         }
3815         else {
3816             var s = p / (2 * Math.PI) * Math.asin(c / a);
3817         }
3818
3819         if (t < 1) {
3820             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3821                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3822         }
3823         return a * Math.pow(2, -10 * (t -= 1)) *
3824                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3825     },
3826
3827
3828
3829     backIn: function (t, b, c, d, s) {
3830         if (typeof s == 'undefined') {
3831             s = 1.70158;
3832         }
3833         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834     },
3835
3836
3837     backOut: function (t, b, c, d, s) {
3838         if (typeof s == 'undefined') {
3839             s = 1.70158;
3840         }
3841         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842     },
3843
3844
3845     backBoth: function (t, b, c, d, s) {
3846         if (typeof s == 'undefined') {
3847             s = 1.70158;
3848         }
3849
3850         if ((t /= d / 2 ) < 1) {
3851             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3852         }
3853         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854     },
3855
3856
3857     bounceIn: function (t, b, c, d) {
3858         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859     },
3860
3861
3862     bounceOut: function (t, b, c, d) {
3863         if ((t /= d) < (1 / 2.75)) {
3864             return c * (7.5625 * t * t) + b;
3865         } else if (t < (2 / 2.75)) {
3866             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3867         } else if (t < (2.5 / 2.75)) {
3868             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3869         }
3870         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871     },
3872
3873
3874     bounceBoth: function (t, b, c, d) {
3875         if (t < d / 2) {
3876             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3877         }
3878         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3879     }
3880 };/*
3881  * Portions of this file are based on pieces of Yahoo User Interface Library
3882  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3883  * YUI licensed under the BSD License:
3884  * http://developer.yahoo.net/yui/license.txt
3885  * <script type="text/javascript">
3886  *
3887  */
3888     (function() {
3889         Roo.lib.Motion = function(el, attributes, duration, method) {
3890             if (el) {
3891                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892             }
3893         };
3894
3895         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896
3897
3898         var Y = Roo.lib;
3899         var superclass = Y.Motion.superclass;
3900         var proto = Y.Motion.prototype;
3901
3902         proto.toString = function() {
3903             var el = this.getEl();
3904             var id = el.id || el.tagName;
3905             return ("Motion " + id);
3906         };
3907
3908         proto.patterns.points = /^points$/i;
3909
3910         proto.setAttribute = function(attr, val, unit) {
3911             if (this.patterns.points.test(attr)) {
3912                 unit = unit || 'px';
3913                 superclass.setAttribute.call(this, 'left', val[0], unit);
3914                 superclass.setAttribute.call(this, 'top', val[1], unit);
3915             } else {
3916                 superclass.setAttribute.call(this, attr, val, unit);
3917             }
3918         };
3919
3920         proto.getAttribute = function(attr) {
3921             if (this.patterns.points.test(attr)) {
3922                 var val = [
3923                         superclass.getAttribute.call(this, 'left'),
3924                         superclass.getAttribute.call(this, 'top')
3925                         ];
3926             } else {
3927                 val = superclass.getAttribute.call(this, attr);
3928             }
3929
3930             return val;
3931         };
3932
3933         proto.doMethod = function(attr, start, end) {
3934             var val = null;
3935
3936             if (this.patterns.points.test(attr)) {
3937                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3938                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3939             } else {
3940                 val = superclass.doMethod.call(this, attr, start, end);
3941             }
3942             return val;
3943         };
3944
3945         proto.setRuntimeAttribute = function(attr) {
3946             if (this.patterns.points.test(attr)) {
3947                 var el = this.getEl();
3948                 var attributes = this.attributes;
3949                 var start;
3950                 var control = attributes['points']['control'] || [];
3951                 var end;
3952                 var i, len;
3953
3954                 if (control.length > 0 && !(control[0] instanceof Array)) {
3955                     control = [control];
3956                 } else {
3957                     var tmp = [];
3958                     for (i = 0,len = control.length; i < len; ++i) {
3959                         tmp[i] = control[i];
3960                     }
3961                     control = tmp;
3962                 }
3963
3964                 Roo.fly(el).position();
3965
3966                 if (isset(attributes['points']['from'])) {
3967                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3968                 }
3969                 else {
3970                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3971                 }
3972
3973                 start = this.getAttribute('points');
3974
3975
3976                 if (isset(attributes['points']['to'])) {
3977                     end = translateValues.call(this, attributes['points']['to'], start);
3978
3979                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3980                     for (i = 0,len = control.length; i < len; ++i) {
3981                         control[i] = translateValues.call(this, control[i], start);
3982                     }
3983
3984
3985                 } else if (isset(attributes['points']['by'])) {
3986                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3987
3988                     for (i = 0,len = control.length; i < len; ++i) {
3989                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990                     }
3991                 }
3992
3993                 this.runtimeAttributes[attr] = [start];
3994
3995                 if (control.length > 0) {
3996                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3997                 }
3998
3999                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4000             }
4001             else {
4002                 superclass.setRuntimeAttribute.call(this, attr);
4003             }
4004         };
4005
4006         var translateValues = function(val, start) {
4007             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4008             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4009
4010             return val;
4011         };
4012
4013         var isset = function(prop) {
4014             return (typeof prop !== 'undefined');
4015         };
4016     })();
4017 /*
4018  * Portions of this file are based on pieces of Yahoo User Interface Library
4019  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4020  * YUI licensed under the BSD License:
4021  * http://developer.yahoo.net/yui/license.txt
4022  * <script type="text/javascript">
4023  *
4024  */
4025     (function() {
4026         Roo.lib.Scroll = function(el, attributes, duration, method) {
4027             if (el) {
4028                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029             }
4030         };
4031
4032         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033
4034
4035         var Y = Roo.lib;
4036         var superclass = Y.Scroll.superclass;
4037         var proto = Y.Scroll.prototype;
4038
4039         proto.toString = function() {
4040             var el = this.getEl();
4041             var id = el.id || el.tagName;
4042             return ("Scroll " + id);
4043         };
4044
4045         proto.doMethod = function(attr, start, end) {
4046             var val = null;
4047
4048             if (attr == 'scroll') {
4049                 val = [
4050                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4051                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052                         ];
4053
4054             } else {
4055                 val = superclass.doMethod.call(this, attr, start, end);
4056             }
4057             return val;
4058         };
4059
4060         proto.getAttribute = function(attr) {
4061             var val = null;
4062             var el = this.getEl();
4063
4064             if (attr == 'scroll') {
4065                 val = [ el.scrollLeft, el.scrollTop ];
4066             } else {
4067                 val = superclass.getAttribute.call(this, attr);
4068             }
4069
4070             return val;
4071         };
4072
4073         proto.setAttribute = function(attr, val, unit) {
4074             var el = this.getEl();
4075
4076             if (attr == 'scroll') {
4077                 el.scrollLeft = val[0];
4078                 el.scrollTop = val[1];
4079             } else {
4080                 superclass.setAttribute.call(this, attr, val, unit);
4081             }
4082         };
4083     })();
4084 /*
4085  * Based on:
4086  * Ext JS Library 1.1.1
4087  * Copyright(c) 2006-2007, Ext JS, LLC.
4088  *
4089  * Originally Released Under LGPL - original licence link has changed is not relivant.
4090  *
4091  * Fork - LGPL
4092  * <script type="text/javascript">
4093  */
4094
4095
4096 // nasty IE9 hack - what a pile of crap that is..
4097
4098  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4099     Range.prototype.createContextualFragment = function (html) {
4100         var doc = window.document;
4101         var container = doc.createElement("div");
4102         container.innerHTML = html;
4103         var frag = doc.createDocumentFragment(), n;
4104         while ((n = container.firstChild)) {
4105             frag.appendChild(n);
4106         }
4107         return frag;
4108     };
4109 }
4110
4111 /**
4112  * @class Roo.DomHelper
4113  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4114  * 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>.
4115  * @singleton
4116  */
4117 Roo.DomHelper = function(){
4118     var tempTableEl = null;
4119     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4120     var tableRe = /^table|tbody|tr|td$/i;
4121     var xmlns = {};
4122     // build as innerHTML where available
4123     /** @ignore */
4124     var createHtml = function(o){
4125         if(typeof o == 'string'){
4126             return o;
4127         }
4128         var b = "";
4129         if(!o.tag){
4130             o.tag = "div";
4131         }
4132         b += "<" + o.tag;
4133         for(var attr in o){
4134             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4135             if(attr == "style"){
4136                 var s = o["style"];
4137                 if(typeof s == "function"){
4138                     s = s.call();
4139                 }
4140                 if(typeof s == "string"){
4141                     b += ' style="' + s + '"';
4142                 }else if(typeof s == "object"){
4143                     b += ' style="';
4144                     for(var key in s){
4145                         if(typeof s[key] != "function"){
4146                             b += key + ":" + s[key] + ";";
4147                         }
4148                     }
4149                     b += '"';
4150                 }
4151             }else{
4152                 if(attr == "cls"){
4153                     b += ' class="' + o["cls"] + '"';
4154                 }else if(attr == "htmlFor"){
4155                     b += ' for="' + o["htmlFor"] + '"';
4156                 }else{
4157                     b += " " + attr + '="' + o[attr] + '"';
4158                 }
4159             }
4160         }
4161         if(emptyTags.test(o.tag)){
4162             b += "/>";
4163         }else{
4164             b += ">";
4165             var cn = o.children || o.cn;
4166             if(cn){
4167                 //http://bugs.kde.org/show_bug.cgi?id=71506
4168                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4169                     for(var i = 0, len = cn.length; i < len; i++) {
4170                         b += createHtml(cn[i], b);
4171                     }
4172                 }else{
4173                     b += createHtml(cn, b);
4174                 }
4175             }
4176             if(o.html){
4177                 b += o.html;
4178             }
4179             b += "</" + o.tag + ">";
4180         }
4181         return b;
4182     };
4183
4184     // build as dom
4185     /** @ignore */
4186     var createDom = function(o, parentNode){
4187          
4188         // defininition craeted..
4189         var ns = false;
4190         if (o.ns && o.ns != 'html') {
4191                
4192             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4193                 xmlns[o.ns] = o.xmlns;
4194                 ns = o.xmlns;
4195             }
4196             if (typeof(xmlns[o.ns]) == 'undefined') {
4197                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4198             }
4199             ns = xmlns[o.ns];
4200         }
4201         
4202         
4203         if (typeof(o) == 'string') {
4204             return parentNode.appendChild(document.createTextNode(o));
4205         }
4206         o.tag = o.tag || div;
4207         if (o.ns && Roo.isIE) {
4208             ns = false;
4209             o.tag = o.ns + ':' + o.tag;
4210             
4211         }
4212         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4213         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4214         for(var attr in o){
4215             
4216             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4217                     attr == "style" || typeof o[attr] == "function") continue;
4218                     
4219             if(attr=="cls" && Roo.isIE){
4220                 el.className = o["cls"];
4221             }else{
4222                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4223                 else el[attr] = o[attr];
4224             }
4225         }
4226         Roo.DomHelper.applyStyles(el, o.style);
4227         var cn = o.children || o.cn;
4228         if(cn){
4229             //http://bugs.kde.org/show_bug.cgi?id=71506
4230              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4231                 for(var i = 0, len = cn.length; i < len; i++) {
4232                     createDom(cn[i], el);
4233                 }
4234             }else{
4235                 createDom(cn, el);
4236             }
4237         }
4238         if(o.html){
4239             el.innerHTML = o.html;
4240         }
4241         if(parentNode){
4242            parentNode.appendChild(el);
4243         }
4244         return el;
4245     };
4246
4247     var ieTable = function(depth, s, h, e){
4248         tempTableEl.innerHTML = [s, h, e].join('');
4249         var i = -1, el = tempTableEl;
4250         while(++i < depth){
4251             el = el.firstChild;
4252         }
4253         return el;
4254     };
4255
4256     // kill repeat to save bytes
4257     var ts = '<table>',
4258         te = '</table>',
4259         tbs = ts+'<tbody>',
4260         tbe = '</tbody>'+te,
4261         trs = tbs + '<tr>',
4262         tre = '</tr>'+tbe;
4263
4264     /**
4265      * @ignore
4266      * Nasty code for IE's broken table implementation
4267      */
4268     var insertIntoTable = function(tag, where, el, html){
4269         if(!tempTableEl){
4270             tempTableEl = document.createElement('div');
4271         }
4272         var node;
4273         var before = null;
4274         if(tag == 'td'){
4275             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4276                 return;
4277             }
4278             if(where == 'beforebegin'){
4279                 before = el;
4280                 el = el.parentNode;
4281             } else{
4282                 before = el.nextSibling;
4283                 el = el.parentNode;
4284             }
4285             node = ieTable(4, trs, html, tre);
4286         }
4287         else if(tag == 'tr'){
4288             if(where == 'beforebegin'){
4289                 before = el;
4290                 el = el.parentNode;
4291                 node = ieTable(3, tbs, html, tbe);
4292             } else if(where == 'afterend'){
4293                 before = el.nextSibling;
4294                 el = el.parentNode;
4295                 node = ieTable(3, tbs, html, tbe);
4296             } else{ // INTO a TR
4297                 if(where == 'afterbegin'){
4298                     before = el.firstChild;
4299                 }
4300                 node = ieTable(4, trs, html, tre);
4301             }
4302         } else if(tag == 'tbody'){
4303             if(where == 'beforebegin'){
4304                 before = el;
4305                 el = el.parentNode;
4306                 node = ieTable(2, ts, html, te);
4307             } else if(where == 'afterend'){
4308                 before = el.nextSibling;
4309                 el = el.parentNode;
4310                 node = ieTable(2, ts, html, te);
4311             } else{
4312                 if(where == 'afterbegin'){
4313                     before = el.firstChild;
4314                 }
4315                 node = ieTable(3, tbs, html, tbe);
4316             }
4317         } else{ // TABLE
4318             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4319                 return;
4320             }
4321             if(where == 'afterbegin'){
4322                 before = el.firstChild;
4323             }
4324             node = ieTable(2, ts, html, te);
4325         }
4326         el.insertBefore(node, before);
4327         return node;
4328     };
4329
4330     return {
4331     /** True to force the use of DOM instead of html fragments @type Boolean */
4332     useDom : false,
4333
4334     /**
4335      * Returns the markup for the passed Element(s) config
4336      * @param {Object} o The Dom object spec (and children)
4337      * @return {String}
4338      */
4339     markup : function(o){
4340         return createHtml(o);
4341     },
4342
4343     /**
4344      * Applies a style specification to an element
4345      * @param {String/HTMLElement} el The element to apply styles to
4346      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4347      * a function which returns such a specification.
4348      */
4349     applyStyles : function(el, styles){
4350         if(styles){
4351            el = Roo.fly(el);
4352            if(typeof styles == "string"){
4353                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4354                var matches;
4355                while ((matches = re.exec(styles)) != null){
4356                    el.setStyle(matches[1], matches[2]);
4357                }
4358            }else if (typeof styles == "object"){
4359                for (var style in styles){
4360                   el.setStyle(style, styles[style]);
4361                }
4362            }else if (typeof styles == "function"){
4363                 Roo.DomHelper.applyStyles(el, styles.call());
4364            }
4365         }
4366     },
4367
4368     /**
4369      * Inserts an HTML fragment into the Dom
4370      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4371      * @param {HTMLElement} el The context element
4372      * @param {String} html The HTML fragmenet
4373      * @return {HTMLElement} The new node
4374      */
4375     insertHtml : function(where, el, html){
4376         where = where.toLowerCase();
4377         if(el.insertAdjacentHTML){
4378             if(tableRe.test(el.tagName)){
4379                 var rs;
4380                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4381                     return rs;
4382                 }
4383             }
4384             switch(where){
4385                 case "beforebegin":
4386                     el.insertAdjacentHTML('BeforeBegin', html);
4387                     return el.previousSibling;
4388                 case "afterbegin":
4389                     el.insertAdjacentHTML('AfterBegin', html);
4390                     return el.firstChild;
4391                 case "beforeend":
4392                     el.insertAdjacentHTML('BeforeEnd', html);
4393                     return el.lastChild;
4394                 case "afterend":
4395                     el.insertAdjacentHTML('AfterEnd', html);
4396                     return el.nextSibling;
4397             }
4398             throw 'Illegal insertion point -> "' + where + '"';
4399         }
4400         var range = el.ownerDocument.createRange();
4401         var frag;
4402         switch(where){
4403              case "beforebegin":
4404                 range.setStartBefore(el);
4405                 frag = range.createContextualFragment(html);
4406                 el.parentNode.insertBefore(frag, el);
4407                 return el.previousSibling;
4408              case "afterbegin":
4409                 if(el.firstChild){
4410                     range.setStartBefore(el.firstChild);
4411                     frag = range.createContextualFragment(html);
4412                     el.insertBefore(frag, el.firstChild);
4413                     return el.firstChild;
4414                 }else{
4415                     el.innerHTML = html;
4416                     return el.firstChild;
4417                 }
4418             case "beforeend":
4419                 if(el.lastChild){
4420                     range.setStartAfter(el.lastChild);
4421                     frag = range.createContextualFragment(html);
4422                     el.appendChild(frag);
4423                     return el.lastChild;
4424                 }else{
4425                     el.innerHTML = html;
4426                     return el.lastChild;
4427                 }
4428             case "afterend":
4429                 range.setStartAfter(el);
4430                 frag = range.createContextualFragment(html);
4431                 el.parentNode.insertBefore(frag, el.nextSibling);
4432                 return el.nextSibling;
4433             }
4434             throw 'Illegal insertion point -> "' + where + '"';
4435     },
4436
4437     /**
4438      * Creates new Dom element(s) and inserts them before el
4439      * @param {String/HTMLElement/Element} el The context element
4440      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4441      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4442      * @return {HTMLElement/Roo.Element} The new node
4443      */
4444     insertBefore : function(el, o, returnElement){
4445         return this.doInsert(el, o, returnElement, "beforeBegin");
4446     },
4447
4448     /**
4449      * Creates new Dom element(s) and inserts them after el
4450      * @param {String/HTMLElement/Element} el The context element
4451      * @param {Object} o The Dom object spec (and children)
4452      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4453      * @return {HTMLElement/Roo.Element} The new node
4454      */
4455     insertAfter : function(el, o, returnElement){
4456         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457     },
4458
4459     /**
4460      * Creates new Dom element(s) and inserts them as the first child of el
4461      * @param {String/HTMLElement/Element} el The context element
4462      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464      * @return {HTMLElement/Roo.Element} The new node
4465      */
4466     insertFirst : function(el, o, returnElement){
4467         return this.doInsert(el, o, returnElement, "afterBegin");
4468     },
4469
4470     // private
4471     doInsert : function(el, o, returnElement, pos, sibling){
4472         el = Roo.getDom(el);
4473         var newNode;
4474         if(this.useDom || o.ns){
4475             newNode = createDom(o, null);
4476             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4477         }else{
4478             var html = createHtml(o);
4479             newNode = this.insertHtml(pos, el, html);
4480         }
4481         return returnElement ? Roo.get(newNode, true) : newNode;
4482     },
4483
4484     /**
4485      * Creates new Dom element(s) and appends them to el
4486      * @param {String/HTMLElement/Element} el The context element
4487      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4488      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4489      * @return {HTMLElement/Roo.Element} The new node
4490      */
4491     append : function(el, o, returnElement){
4492         el = Roo.getDom(el);
4493         var newNode;
4494         if(this.useDom || o.ns){
4495             newNode = createDom(o, null);
4496             el.appendChild(newNode);
4497         }else{
4498             var html = createHtml(o);
4499             newNode = this.insertHtml("beforeEnd", el, html);
4500         }
4501         return returnElement ? Roo.get(newNode, true) : newNode;
4502     },
4503
4504     /**
4505      * Creates new Dom element(s) and overwrites the contents of el with them
4506      * @param {String/HTMLElement/Element} el The context element
4507      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4508      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4509      * @return {HTMLElement/Roo.Element} The new node
4510      */
4511     overwrite : function(el, o, returnElement){
4512         el = Roo.getDom(el);
4513         if (o.ns) {
4514           
4515             while (el.childNodes.length) {
4516                 el.removeChild(el.firstChild);
4517             }
4518             createDom(o, el);
4519         } else {
4520             el.innerHTML = createHtml(o);   
4521         }
4522         
4523         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524     },
4525
4526     /**
4527      * Creates a new Roo.DomHelper.Template from the Dom object spec
4528      * @param {Object} o The Dom object spec (and children)
4529      * @return {Roo.DomHelper.Template} The new template
4530      */
4531     createTemplate : function(o){
4532         var html = createHtml(o);
4533         return new Roo.Template(html);
4534     }
4535     };
4536 }();
4537 /*
4538  * Based on:
4539  * Ext JS Library 1.1.1
4540  * Copyright(c) 2006-2007, Ext JS, LLC.
4541  *
4542  * Originally Released Under LGPL - original licence link has changed is not relivant.
4543  *
4544  * Fork - LGPL
4545  * <script type="text/javascript">
4546  */
4547  
4548 /**
4549 * @class Roo.Template
4550 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4551 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4552 * Usage:
4553 <pre><code>
4554 var t = new Roo.Template({
4555     html :  '&lt;div name="{id}"&gt;' + 
4556         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4557         '&lt;/div&gt;',
4558     myformat: function (value, allValues) {
4559         return 'XX' + value;
4560     }
4561 });
4562 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4563 </code></pre>
4564 * For more information see this blog post with examples:
4565 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4566      - Create Elements using DOM, HTML fragments and Templates</a>. 
4567 * @constructor
4568 * @param {Object} cfg - Configuration object.
4569 */
4570 Roo.Template = function(cfg){
4571     // BC!
4572     if(cfg instanceof Array){
4573         cfg = cfg.join("");
4574     }else if(arguments.length > 1){
4575         cfg = Array.prototype.join.call(arguments, "");
4576     }
4577     
4578     
4579     if (typeof(cfg) == 'object') {
4580         Roo.apply(this,cfg)
4581     } else {
4582         // bc
4583         this.html = cfg;
4584     }
4585     if (this.url) {
4586         this.load();
4587     }
4588     
4589 };
4590 Roo.Template.prototype = {
4591     
4592     /**
4593      * @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..
4594      *                    it should be fixed so that template is observable...
4595      */
4596     url : false,
4597     /**
4598      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599      */
4600     html : '',
4601     /**
4602      * Returns an HTML fragment of this template with the specified values applied.
4603      * @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'})
4604      * @return {String} The HTML fragment
4605      */
4606     applyTemplate : function(values){
4607         try {
4608            
4609             if(this.compiled){
4610                 return this.compiled(values);
4611             }
4612             var useF = this.disableFormats !== true;
4613             var fm = Roo.util.Format, tpl = this;
4614             var fn = function(m, name, format, args){
4615                 if(format && useF){
4616                     if(format.substr(0, 5) == "this."){
4617                         return tpl.call(format.substr(5), values[name], values);
4618                     }else{
4619                         if(args){
4620                             // quoted values are required for strings in compiled templates, 
4621                             // but for non compiled we need to strip them
4622                             // quoted reversed for jsmin
4623                             var re = /^\s*['"](.*)["']\s*$/;
4624                             args = args.split(',');
4625                             for(var i = 0, len = args.length; i < len; i++){
4626                                 args[i] = args[i].replace(re, "$1");
4627                             }
4628                             args = [values[name]].concat(args);
4629                         }else{
4630                             args = [values[name]];
4631                         }
4632                         return fm[format].apply(fm, args);
4633                     }
4634                 }else{
4635                     return values[name] !== undefined ? values[name] : "";
4636                 }
4637             };
4638             return this.html.replace(this.re, fn);
4639         } catch (e) {
4640             Roo.log(e);
4641             throw e;
4642         }
4643          
4644     },
4645     
4646     loading : false,
4647       
4648     load : function ()
4649     {
4650          
4651         if (this.loading) {
4652             return;
4653         }
4654         var _t = this;
4655         
4656         this.loading = true;
4657         this.compiled = false;
4658         
4659         var cx = new Roo.data.Connection();
4660         cx.request({
4661             url : this.url,
4662             method : 'GET',
4663             success : function (response) {
4664                 _t.loading = false;
4665                 _t.html = response.responseText;
4666                 _t.url = false;
4667                 _t.compile();
4668              },
4669             failure : function(response) {
4670                 Roo.log("Template failed to load from " + _t.url);
4671                 _t.loading = false;
4672             }
4673         });
4674     },
4675
4676     /**
4677      * Sets the HTML used as the template and optionally compiles it.
4678      * @param {String} html
4679      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4680      * @return {Roo.Template} this
4681      */
4682     set : function(html, compile){
4683         this.html = html;
4684         this.compiled = null;
4685         if(compile){
4686             this.compile();
4687         }
4688         return this;
4689     },
4690     
4691     /**
4692      * True to disable format functions (defaults to false)
4693      * @type Boolean
4694      */
4695     disableFormats : false,
4696     
4697     /**
4698     * The regular expression used to match template variables 
4699     * @type RegExp
4700     * @property 
4701     */
4702     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4703     
4704     /**
4705      * Compiles the template into an internal function, eliminating the RegEx overhead.
4706      * @return {Roo.Template} this
4707      */
4708     compile : function(){
4709         var fm = Roo.util.Format;
4710         var useF = this.disableFormats !== true;
4711         var sep = Roo.isGecko ? "+" : ",";
4712         var fn = function(m, name, format, args){
4713             if(format && useF){
4714                 args = args ? ',' + args : "";
4715                 if(format.substr(0, 5) != "this."){
4716                     format = "fm." + format + '(';
4717                 }else{
4718                     format = 'this.call("'+ format.substr(5) + '", ';
4719                     args = ", values";
4720                 }
4721             }else{
4722                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4723             }
4724             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4725         };
4726         var body;
4727         // branched to use + in gecko and [].join() in others
4728         if(Roo.isGecko){
4729             body = "this.compiled = function(values){ return '" +
4730                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4731                     "';};";
4732         }else{
4733             body = ["this.compiled = function(values){ return ['"];
4734             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4735             body.push("'].join('');};");
4736             body = body.join('');
4737         }
4738         /**
4739          * eval:var:values
4740          * eval:var:fm
4741          */
4742         eval(body);
4743         return this;
4744     },
4745     
4746     // private function used to call members
4747     call : function(fnName, value, allValues){
4748         return this[fnName](value, allValues);
4749     },
4750     
4751     /**
4752      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4753      * @param {String/HTMLElement/Roo.Element} el The context element
4754      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4755      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4756      * @return {HTMLElement/Roo.Element} The new node or Element
4757      */
4758     insertFirst: function(el, values, returnElement){
4759         return this.doInsert('afterBegin', el, values, returnElement);
4760     },
4761
4762     /**
4763      * Applies the supplied values to the template and inserts the new node(s) before el.
4764      * @param {String/HTMLElement/Roo.Element} el The context element
4765      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4766      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4767      * @return {HTMLElement/Roo.Element} The new node or Element
4768      */
4769     insertBefore: function(el, values, returnElement){
4770         return this.doInsert('beforeBegin', el, values, returnElement);
4771     },
4772
4773     /**
4774      * Applies the supplied values to the template and inserts the new node(s) after el.
4775      * @param {String/HTMLElement/Roo.Element} el The context element
4776      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4777      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778      * @return {HTMLElement/Roo.Element} The new node or Element
4779      */
4780     insertAfter : function(el, values, returnElement){
4781         return this.doInsert('afterEnd', el, values, returnElement);
4782     },
4783     
4784     /**
4785      * Applies the supplied values to the template and appends the new node(s) to el.
4786      * @param {String/HTMLElement/Roo.Element} el The context element
4787      * @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'})
4788      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789      * @return {HTMLElement/Roo.Element} The new node or Element
4790      */
4791     append : function(el, values, returnElement){
4792         return this.doInsert('beforeEnd', el, values, returnElement);
4793     },
4794
4795     doInsert : function(where, el, values, returnEl){
4796         el = Roo.getDom(el);
4797         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4798         return returnEl ? Roo.get(newNode, true) : newNode;
4799     },
4800
4801     /**
4802      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4803      * @param {String/HTMLElement/Roo.Element} el The context element
4804      * @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'})
4805      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4806      * @return {HTMLElement/Roo.Element} The new node or Element
4807      */
4808     overwrite : function(el, values, returnElement){
4809         el = Roo.getDom(el);
4810         el.innerHTML = this.applyTemplate(values);
4811         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812     }
4813 };
4814 /**
4815  * Alias for {@link #applyTemplate}
4816  * @method
4817  */
4818 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4819
4820 // backwards compat
4821 Roo.DomHelper.Template = Roo.Template;
4822
4823 /**
4824  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4825  * @param {String/HTMLElement} el A DOM element or its id
4826  * @returns {Roo.Template} The created template
4827  * @static
4828  */
4829 Roo.Template.from = function(el){
4830     el = Roo.getDom(el);
4831     return new Roo.Template(el.value || el.innerHTML);
4832 };/*
4833  * Based on:
4834  * Ext JS Library 1.1.1
4835  * Copyright(c) 2006-2007, Ext JS, LLC.
4836  *
4837  * Originally Released Under LGPL - original licence link has changed is not relivant.
4838  *
4839  * Fork - LGPL
4840  * <script type="text/javascript">
4841  */
4842  
4843
4844 /*
4845  * This is code is also distributed under MIT license for use
4846  * with jQuery and prototype JavaScript libraries.
4847  */
4848 /**
4849  * @class Roo.DomQuery
4850 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).
4851 <p>
4852 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>
4853
4854 <p>
4855 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.
4856 </p>
4857 <h4>Element Selectors:</h4>
4858 <ul class="list">
4859     <li> <b>*</b> any element</li>
4860     <li> <b>E</b> an element with the tag E</li>
4861     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4862     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4863     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4864     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4865 </ul>
4866 <h4>Attribute Selectors:</h4>
4867 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4868 <ul class="list">
4869     <li> <b>E[foo]</b> has an attribute "foo"</li>
4870     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4871     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4872     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4873     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4874     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4875     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4876 </ul>
4877 <h4>Pseudo Classes:</h4>
4878 <ul class="list">
4879     <li> <b>E:first-child</b> E is the first child of its parent</li>
4880     <li> <b>E:last-child</b> E is the last child of its parent</li>
4881     <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>
4882     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4883     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4884     <li> <b>E:only-child</b> E is the only child of its parent</li>
4885     <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>
4886     <li> <b>E:first</b> the first E in the resultset</li>
4887     <li> <b>E:last</b> the last E in the resultset</li>
4888     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4889     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4890     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4891     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4892     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4893     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4894     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4895     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4896     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4897 </ul>
4898 <h4>CSS Value Selectors:</h4>
4899 <ul class="list">
4900     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4901     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4902     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4903     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4904     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4905     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 </ul>
4907  * @singleton
4908  */
4909 Roo.DomQuery = function(){
4910     var cache = {}, simpleCache = {}, valueCache = {};
4911     var nonSpace = /\S/;
4912     var trimRe = /^\s+|\s+$/g;
4913     var tplRe = /\{(\d+)\}/g;
4914     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4915     var tagTokenRe = /^(#)?([\w-\*]+)/;
4916     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4917
4918     function child(p, index){
4919         var i = 0;
4920         var n = p.firstChild;
4921         while(n){
4922             if(n.nodeType == 1){
4923                if(++i == index){
4924                    return n;
4925                }
4926             }
4927             n = n.nextSibling;
4928         }
4929         return null;
4930     };
4931
4932     function next(n){
4933         while((n = n.nextSibling) && n.nodeType != 1);
4934         return n;
4935     };
4936
4937     function prev(n){
4938         while((n = n.previousSibling) && n.nodeType != 1);
4939         return n;
4940     };
4941
4942     function children(d){
4943         var n = d.firstChild, ni = -1;
4944             while(n){
4945                 var nx = n.nextSibling;
4946                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4947                     d.removeChild(n);
4948                 }else{
4949                     n.nodeIndex = ++ni;
4950                 }
4951                 n = nx;
4952             }
4953             return this;
4954         };
4955
4956     function byClassName(c, a, v){
4957         if(!v){
4958             return c;
4959         }
4960         var r = [], ri = -1, cn;
4961         for(var i = 0, ci; ci = c[i]; i++){
4962             if((' '+ci.className+' ').indexOf(v) != -1){
4963                 r[++ri] = ci;
4964             }
4965         }
4966         return r;
4967     };
4968
4969     function attrValue(n, attr){
4970         if(!n.tagName && typeof n.length != "undefined"){
4971             n = n[0];
4972         }
4973         if(!n){
4974             return null;
4975         }
4976         if(attr == "for"){
4977             return n.htmlFor;
4978         }
4979         if(attr == "class" || attr == "className"){
4980             return n.className;
4981         }
4982         return n.getAttribute(attr) || n[attr];
4983
4984     };
4985
4986     function getNodes(ns, mode, tagName){
4987         var result = [], ri = -1, cs;
4988         if(!ns){
4989             return result;
4990         }
4991         tagName = tagName || "*";
4992         if(typeof ns.getElementsByTagName != "undefined"){
4993             ns = [ns];
4994         }
4995         if(!mode){
4996             for(var i = 0, ni; ni = ns[i]; i++){
4997                 cs = ni.getElementsByTagName(tagName);
4998                 for(var j = 0, ci; ci = cs[j]; j++){
4999                     result[++ri] = ci;
5000                 }
5001             }
5002         }else if(mode == "/" || mode == ">"){
5003             var utag = tagName.toUpperCase();
5004             for(var i = 0, ni, cn; ni = ns[i]; i++){
5005                 cn = ni.children || ni.childNodes;
5006                 for(var j = 0, cj; cj = cn[j]; j++){
5007                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5008                         result[++ri] = cj;
5009                     }
5010                 }
5011             }
5012         }else if(mode == "+"){
5013             var utag = tagName.toUpperCase();
5014             for(var i = 0, n; n = ns[i]; i++){
5015                 while((n = n.nextSibling) && n.nodeType != 1);
5016                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017                     result[++ri] = n;
5018                 }
5019             }
5020         }else if(mode == "~"){
5021             for(var i = 0, n; n = ns[i]; i++){
5022                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5023                 if(n){
5024                     result[++ri] = n;
5025                 }
5026             }
5027         }
5028         return result;
5029     };
5030
5031     function concat(a, b){
5032         if(b.slice){
5033             return a.concat(b);
5034         }
5035         for(var i = 0, l = b.length; i < l; i++){
5036             a[a.length] = b[i];
5037         }
5038         return a;
5039     }
5040
5041     function byTag(cs, tagName){
5042         if(cs.tagName || cs == document){
5043             cs = [cs];
5044         }
5045         if(!tagName){
5046             return cs;
5047         }
5048         var r = [], ri = -1;
5049         tagName = tagName.toLowerCase();
5050         for(var i = 0, ci; ci = cs[i]; i++){
5051             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5052                 r[++ri] = ci;
5053             }
5054         }
5055         return r;
5056     };
5057
5058     function byId(cs, attr, id){
5059         if(cs.tagName || cs == document){
5060             cs = [cs];
5061         }
5062         if(!id){
5063             return cs;
5064         }
5065         var r = [], ri = -1;
5066         for(var i = 0,ci; ci = cs[i]; i++){
5067             if(ci && ci.id == id){
5068                 r[++ri] = ci;
5069                 return r;
5070             }
5071         }
5072         return r;
5073     };
5074
5075     function byAttribute(cs, attr, value, op, custom){
5076         var r = [], ri = -1, st = custom=="{";
5077         var f = Roo.DomQuery.operators[op];
5078         for(var i = 0, ci; ci = cs[i]; i++){
5079             var a;
5080             if(st){
5081                 a = Roo.DomQuery.getStyle(ci, attr);
5082             }
5083             else if(attr == "class" || attr == "className"){
5084                 a = ci.className;
5085             }else if(attr == "for"){
5086                 a = ci.htmlFor;
5087             }else if(attr == "href"){
5088                 a = ci.getAttribute("href", 2);
5089             }else{
5090                 a = ci.getAttribute(attr);
5091             }
5092             if((f && f(a, value)) || (!f && a)){
5093                 r[++ri] = ci;
5094             }
5095         }
5096         return r;
5097     };
5098
5099     function byPseudo(cs, name, value){
5100         return Roo.DomQuery.pseudos[name](cs, value);
5101     };
5102
5103     // This is for IE MSXML which does not support expandos.
5104     // IE runs the same speed using setAttribute, however FF slows way down
5105     // and Safari completely fails so they need to continue to use expandos.
5106     var isIE = window.ActiveXObject ? true : false;
5107
5108     // this eval is stop the compressor from
5109     // renaming the variable to something shorter
5110     
5111     /** eval:var:batch */
5112     var batch = 30803; 
5113
5114     var key = 30803;
5115
5116     function nodupIEXml(cs){
5117         var d = ++key;
5118         cs[0].setAttribute("_nodup", d);
5119         var r = [cs[0]];
5120         for(var i = 1, len = cs.length; i < len; i++){
5121             var c = cs[i];
5122             if(!c.getAttribute("_nodup") != d){
5123                 c.setAttribute("_nodup", d);
5124                 r[r.length] = c;
5125             }
5126         }
5127         for(var i = 0, len = cs.length; i < len; i++){
5128             cs[i].removeAttribute("_nodup");
5129         }
5130         return r;
5131     }
5132
5133     function nodup(cs){
5134         if(!cs){
5135             return [];
5136         }
5137         var len = cs.length, c, i, r = cs, cj, ri = -1;
5138         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5139             return cs;
5140         }
5141         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5142             return nodupIEXml(cs);
5143         }
5144         var d = ++key;
5145         cs[0]._nodup = d;
5146         for(i = 1; c = cs[i]; i++){
5147             if(c._nodup != d){
5148                 c._nodup = d;
5149             }else{
5150                 r = [];
5151                 for(var j = 0; j < i; j++){
5152                     r[++ri] = cs[j];
5153                 }
5154                 for(j = i+1; cj = cs[j]; j++){
5155                     if(cj._nodup != d){
5156                         cj._nodup = d;
5157                         r[++ri] = cj;
5158                     }
5159                 }
5160                 return r;
5161             }
5162         }
5163         return r;
5164     }
5165
5166     function quickDiffIEXml(c1, c2){
5167         var d = ++key;
5168         for(var i = 0, len = c1.length; i < len; i++){
5169             c1[i].setAttribute("_qdiff", d);
5170         }
5171         var r = [];
5172         for(var i = 0, len = c2.length; i < len; i++){
5173             if(c2[i].getAttribute("_qdiff") != d){
5174                 r[r.length] = c2[i];
5175             }
5176         }
5177         for(var i = 0, len = c1.length; i < len; i++){
5178            c1[i].removeAttribute("_qdiff");
5179         }
5180         return r;
5181     }
5182
5183     function quickDiff(c1, c2){
5184         var len1 = c1.length;
5185         if(!len1){
5186             return c2;
5187         }
5188         if(isIE && c1[0].selectSingleNode){
5189             return quickDiffIEXml(c1, c2);
5190         }
5191         var d = ++key;
5192         for(var i = 0; i < len1; i++){
5193             c1[i]._qdiff = d;
5194         }
5195         var r = [];
5196         for(var i = 0, len = c2.length; i < len; i++){
5197             if(c2[i]._qdiff != d){
5198                 r[r.length] = c2[i];
5199             }
5200         }
5201         return r;
5202     }
5203
5204     function quickId(ns, mode, root, id){
5205         if(ns == root){
5206            var d = root.ownerDocument || root;
5207            return d.getElementById(id);
5208         }
5209         ns = getNodes(ns, mode, "*");
5210         return byId(ns, null, id);
5211     }
5212
5213     return {
5214         getStyle : function(el, name){
5215             return Roo.fly(el).getStyle(name);
5216         },
5217         /**
5218          * Compiles a selector/xpath query into a reusable function. The returned function
5219          * takes one parameter "root" (optional), which is the context node from where the query should start.
5220          * @param {String} selector The selector/xpath query
5221          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5222          * @return {Function}
5223          */
5224         compile : function(path, type){
5225             type = type || "select";
5226             
5227             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5228             var q = path, mode, lq;
5229             var tk = Roo.DomQuery.matchers;
5230             var tklen = tk.length;
5231             var mm;
5232
5233             // accept leading mode switch
5234             var lmode = q.match(modeRe);
5235             if(lmode && lmode[1]){
5236                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5237                 q = q.replace(lmode[1], "");
5238             }
5239             // strip leading slashes
5240             while(path.substr(0, 1)=="/"){
5241                 path = path.substr(1);
5242             }
5243
5244             while(q && lq != q){
5245                 lq = q;
5246                 var tm = q.match(tagTokenRe);
5247                 if(type == "select"){
5248                     if(tm){
5249                         if(tm[1] == "#"){
5250                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5251                         }else{
5252                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5253                         }
5254                         q = q.replace(tm[0], "");
5255                     }else if(q.substr(0, 1) != '@'){
5256                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5257                     }
5258                 }else{
5259                     if(tm){
5260                         if(tm[1] == "#"){
5261                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5262                         }else{
5263                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5264                         }
5265                         q = q.replace(tm[0], "");
5266                     }
5267                 }
5268                 while(!(mm = q.match(modeRe))){
5269                     var matched = false;
5270                     for(var j = 0; j < tklen; j++){
5271                         var t = tk[j];
5272                         var m = q.match(t.re);
5273                         if(m){
5274                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5275                                                     return m[i];
5276                                                 });
5277                             q = q.replace(m[0], "");
5278                             matched = true;
5279                             break;
5280                         }
5281                     }
5282                     // prevent infinite loop on bad selector
5283                     if(!matched){
5284                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5285                     }
5286                 }
5287                 if(mm[1]){
5288                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5289                     q = q.replace(mm[1], "");
5290                 }
5291             }
5292             fn[fn.length] = "return nodup(n);\n}";
5293             
5294              /** 
5295               * list of variables that need from compression as they are used by eval.
5296              *  eval:var:batch 
5297              *  eval:var:nodup
5298              *  eval:var:byTag
5299              *  eval:var:ById
5300              *  eval:var:getNodes
5301              *  eval:var:quickId
5302              *  eval:var:mode
5303              *  eval:var:root
5304              *  eval:var:n
5305              *  eval:var:byClassName
5306              *  eval:var:byPseudo
5307              *  eval:var:byAttribute
5308              *  eval:var:attrValue
5309              * 
5310              **/ 
5311             eval(fn.join(""));
5312             return f;
5313         },
5314
5315         /**
5316          * Selects a group of elements.
5317          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5318          * @param {Node} root (optional) The start of the query (defaults to document).
5319          * @return {Array}
5320          */
5321         select : function(path, root, type){
5322             if(!root || root == document){
5323                 root = document;
5324             }
5325             if(typeof root == "string"){
5326                 root = document.getElementById(root);
5327             }
5328             var paths = path.split(",");
5329             var results = [];
5330             for(var i = 0, len = paths.length; i < len; i++){
5331                 var p = paths[i].replace(trimRe, "");
5332                 if(!cache[p]){
5333                     cache[p] = Roo.DomQuery.compile(p);
5334                     if(!cache[p]){
5335                         throw p + " is not a valid selector";
5336                     }
5337                 }
5338                 var result = cache[p](root);
5339                 if(result && result != document){
5340                     results = results.concat(result);
5341                 }
5342             }
5343             if(paths.length > 1){
5344                 return nodup(results);
5345             }
5346             return results;
5347         },
5348
5349         /**
5350          * Selects a single element.
5351          * @param {String} selector The selector/xpath query
5352          * @param {Node} root (optional) The start of the query (defaults to document).
5353          * @return {Element}
5354          */
5355         selectNode : function(path, root){
5356             return Roo.DomQuery.select(path, root)[0];
5357         },
5358
5359         /**
5360          * Selects the value of a node, optionally replacing null with the defaultValue.
5361          * @param {String} selector The selector/xpath query
5362          * @param {Node} root (optional) The start of the query (defaults to document).
5363          * @param {String} defaultValue
5364          */
5365         selectValue : function(path, root, defaultValue){
5366             path = path.replace(trimRe, "");
5367             if(!valueCache[path]){
5368                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5369             }
5370             var n = valueCache[path](root);
5371             n = n[0] ? n[0] : n;
5372             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5373             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374         },
5375
5376         /**
5377          * Selects the value of a node, parsing integers and floats.
5378          * @param {String} selector The selector/xpath query
5379          * @param {Node} root (optional) The start of the query (defaults to document).
5380          * @param {Number} defaultValue
5381          * @return {Number}
5382          */
5383         selectNumber : function(path, root, defaultValue){
5384             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5385             return parseFloat(v);
5386         },
5387
5388         /**
5389          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5390          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5391          * @param {String} selector The simple selector to test
5392          * @return {Boolean}
5393          */
5394         is : function(el, ss){
5395             if(typeof el == "string"){
5396                 el = document.getElementById(el);
5397             }
5398             var isArray = (el instanceof Array);
5399             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5400             return isArray ? (result.length == el.length) : (result.length > 0);
5401         },
5402
5403         /**
5404          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5405          * @param {Array} el An array of elements to filter
5406          * @param {String} selector The simple selector to test
5407          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5408          * the selector instead of the ones that match
5409          * @return {Array}
5410          */
5411         filter : function(els, ss, nonMatches){
5412             ss = ss.replace(trimRe, "");
5413             if(!simpleCache[ss]){
5414                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5415             }
5416             var result = simpleCache[ss](els);
5417             return nonMatches ? quickDiff(result, els) : result;
5418         },
5419
5420         /**
5421          * Collection of matching regular expressions and code snippets.
5422          */
5423         matchers : [{
5424                 re: /^\.([\w-]+)/,
5425                 select: 'n = byClassName(n, null, " {1} ");'
5426             }, {
5427                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5428                 select: 'n = byPseudo(n, "{1}", "{2}");'
5429             },{
5430                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5431                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5432             }, {
5433                 re: /^#([\w-]+)/,
5434                 select: 'n = byId(n, null, "{1}");'
5435             },{
5436                 re: /^@([\w-]+)/,
5437                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5438             }
5439         ],
5440
5441         /**
5442          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5443          * 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;.
5444          */
5445         operators : {
5446             "=" : function(a, v){
5447                 return a == v;
5448             },
5449             "!=" : function(a, v){
5450                 return a != v;
5451             },
5452             "^=" : function(a, v){
5453                 return a && a.substr(0, v.length) == v;
5454             },
5455             "$=" : function(a, v){
5456                 return a && a.substr(a.length-v.length) == v;
5457             },
5458             "*=" : function(a, v){
5459                 return a && a.indexOf(v) !== -1;
5460             },
5461             "%=" : function(a, v){
5462                 return (a % v) == 0;
5463             },
5464             "|=" : function(a, v){
5465                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5466             },
5467             "~=" : function(a, v){
5468                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5469             }
5470         },
5471
5472         /**
5473          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5474          * and the argument (if any) supplied in the selector.
5475          */
5476         pseudos : {
5477             "first-child" : function(c){
5478                 var r = [], ri = -1, n;
5479                 for(var i = 0, ci; ci = n = c[i]; i++){
5480                     while((n = n.previousSibling) && n.nodeType != 1);
5481                     if(!n){
5482                         r[++ri] = ci;
5483                     }
5484                 }
5485                 return r;
5486             },
5487
5488             "last-child" : function(c){
5489                 var r = [], ri = -1, n;
5490                 for(var i = 0, ci; ci = n = c[i]; i++){
5491                     while((n = n.nextSibling) && n.nodeType != 1);
5492                     if(!n){
5493                         r[++ri] = ci;
5494                     }
5495                 }
5496                 return r;
5497             },
5498
5499             "nth-child" : function(c, a) {
5500                 var r = [], ri = -1;
5501                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5502                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5503                 for(var i = 0, n; n = c[i]; i++){
5504                     var pn = n.parentNode;
5505                     if (batch != pn._batch) {
5506                         var j = 0;
5507                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5508                             if(cn.nodeType == 1){
5509                                cn.nodeIndex = ++j;
5510                             }
5511                         }
5512                         pn._batch = batch;
5513                     }
5514                     if (f == 1) {
5515                         if (l == 0 || n.nodeIndex == l){
5516                             r[++ri] = n;
5517                         }
5518                     } else if ((n.nodeIndex + l) % f == 0){
5519                         r[++ri] = n;
5520                     }
5521                 }
5522
5523                 return r;
5524             },
5525
5526             "only-child" : function(c){
5527                 var r = [], ri = -1;;
5528                 for(var i = 0, ci; ci = c[i]; i++){
5529                     if(!prev(ci) && !next(ci)){
5530                         r[++ri] = ci;
5531                     }
5532                 }
5533                 return r;
5534             },
5535
5536             "empty" : function(c){
5537                 var r = [], ri = -1;
5538                 for(var i = 0, ci; ci = c[i]; i++){
5539                     var cns = ci.childNodes, j = 0, cn, empty = true;
5540                     while(cn = cns[j]){
5541                         ++j;
5542                         if(cn.nodeType == 1 || cn.nodeType == 3){
5543                             empty = false;
5544                             break;
5545                         }
5546                     }
5547                     if(empty){
5548                         r[++ri] = ci;
5549                     }
5550                 }
5551                 return r;
5552             },
5553
5554             "contains" : function(c, v){
5555                 var r = [], ri = -1;
5556                 for(var i = 0, ci; ci = c[i]; i++){
5557                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5558                         r[++ri] = ci;
5559                     }
5560                 }
5561                 return r;
5562             },
5563
5564             "nodeValue" : function(c, v){
5565                 var r = [], ri = -1;
5566                 for(var i = 0, ci; ci = c[i]; i++){
5567                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5568                         r[++ri] = ci;
5569                     }
5570                 }
5571                 return r;
5572             },
5573
5574             "checked" : function(c){
5575                 var r = [], ri = -1;
5576                 for(var i = 0, ci; ci = c[i]; i++){
5577                     if(ci.checked == true){
5578                         r[++ri] = ci;
5579                     }
5580                 }
5581                 return r;
5582             },
5583
5584             "not" : function(c, ss){
5585                 return Roo.DomQuery.filter(c, ss, true);
5586             },
5587
5588             "odd" : function(c){
5589                 return this["nth-child"](c, "odd");
5590             },
5591
5592             "even" : function(c){
5593                 return this["nth-child"](c, "even");
5594             },
5595
5596             "nth" : function(c, a){
5597                 return c[a-1] || [];
5598             },
5599
5600             "first" : function(c){
5601                 return c[0] || [];
5602             },
5603
5604             "last" : function(c){
5605                 return c[c.length-1] || [];
5606             },
5607
5608             "has" : function(c, ss){
5609                 var s = Roo.DomQuery.select;
5610                 var r = [], ri = -1;
5611                 for(var i = 0, ci; ci = c[i]; i++){
5612                     if(s(ss, ci).length > 0){
5613                         r[++ri] = ci;
5614                     }
5615                 }
5616                 return r;
5617             },
5618
5619             "next" : function(c, ss){
5620                 var is = Roo.DomQuery.is;
5621                 var r = [], ri = -1;
5622                 for(var i = 0, ci; ci = c[i]; i++){
5623                     var n = next(ci);
5624                     if(n && is(n, ss)){
5625                         r[++ri] = ci;
5626                     }
5627                 }
5628                 return r;
5629             },
5630
5631             "prev" : function(c, ss){
5632                 var is = Roo.DomQuery.is;
5633                 var r = [], ri = -1;
5634                 for(var i = 0, ci; ci = c[i]; i++){
5635                     var n = prev(ci);
5636                     if(n && is(n, ss)){
5637                         r[++ri] = ci;
5638                     }
5639                 }
5640                 return r;
5641             }
5642         }
5643     };
5644 }();
5645
5646 /**
5647  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5648  * @param {String} path The selector/xpath query
5649  * @param {Node} root (optional) The start of the query (defaults to document).
5650  * @return {Array}
5651  * @member Roo
5652  * @method query
5653  */
5654 Roo.query = Roo.DomQuery.select;
5655 /*
5656  * Based on:
5657  * Ext JS Library 1.1.1
5658  * Copyright(c) 2006-2007, Ext JS, LLC.
5659  *
5660  * Originally Released Under LGPL - original licence link has changed is not relivant.
5661  *
5662  * Fork - LGPL
5663  * <script type="text/javascript">
5664  */
5665
5666 /**
5667  * @class Roo.util.Observable
5668  * Base class that provides a common interface for publishing events. Subclasses are expected to
5669  * to have a property "events" with all the events defined.<br>
5670  * For example:
5671  * <pre><code>
5672  Employee = function(name){
5673     this.name = name;
5674     this.addEvents({
5675         "fired" : true,
5676         "quit" : true
5677     });
5678  }
5679  Roo.extend(Employee, Roo.util.Observable);
5680 </code></pre>
5681  * @param {Object} config properties to use (incuding events / listeners)
5682  */
5683
5684 Roo.util.Observable = function(cfg){
5685     
5686     cfg = cfg|| {};
5687     this.addEvents(cfg.events || {});
5688     if (cfg.events) {
5689         delete cfg.events; // make sure
5690     }
5691      
5692     Roo.apply(this, cfg);
5693     
5694     if(this.listeners){
5695         this.on(this.listeners);
5696         delete this.listeners;
5697     }
5698 };
5699 Roo.util.Observable.prototype = {
5700     /** 
5701  * @cfg {Object} listeners  list of events and functions to call for this object, 
5702  * For example :
5703  * <pre><code>
5704     listeners :  { 
5705        'click' : function(e) {
5706            ..... 
5707         } ,
5708         .... 
5709     } 
5710   </code></pre>
5711  */
5712     
5713     
5714     /**
5715      * Fires the specified event with the passed parameters (minus the event name).
5716      * @param {String} eventName
5717      * @param {Object...} args Variable number of parameters are passed to handlers
5718      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5719      */
5720     fireEvent : function(){
5721         var ce = this.events[arguments[0].toLowerCase()];
5722         if(typeof ce == "object"){
5723             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5724         }else{
5725             return true;
5726         }
5727     },
5728
5729     // private
5730     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5731
5732     /**
5733      * Appends an event handler to this component
5734      * @param {String}   eventName The type of event to listen for
5735      * @param {Function} handler The method the event invokes
5736      * @param {Object}   scope (optional) The scope in which to execute the handler
5737      * function. The handler function's "this" context.
5738      * @param {Object}   options (optional) An object containing handler configuration
5739      * properties. This may contain any of the following properties:<ul>
5740      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5741      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5742      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5743      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5744      * by the specified number of milliseconds. If the event fires again within that time, the original
5745      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5746      * </ul><br>
5747      * <p>
5748      * <b>Combining Options</b><br>
5749      * Using the options argument, it is possible to combine different types of listeners:<br>
5750      * <br>
5751      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5752                 <pre><code>
5753                 el.on('click', this.onClick, this, {
5754                         single: true,
5755                 delay: 100,
5756                 forumId: 4
5757                 });
5758                 </code></pre>
5759      * <p>
5760      * <b>Attaching multiple handlers in 1 call</b><br>
5761      * The method also allows for a single argument to be passed which is a config object containing properties
5762      * which specify multiple handlers.
5763      * <pre><code>
5764                 el.on({
5765                         'click': {
5766                         fn: this.onClick,
5767                         scope: this,
5768                         delay: 100
5769                 }, 
5770                 'mouseover': {
5771                         fn: this.onMouseOver,
5772                         scope: this
5773                 },
5774                 'mouseout': {
5775                         fn: this.onMouseOut,
5776                         scope: this
5777                 }
5778                 });
5779                 </code></pre>
5780      * <p>
5781      * Or a shorthand syntax which passes the same scope object to all handlers:
5782         <pre><code>
5783                 el.on({
5784                         'click': this.onClick,
5785                 'mouseover': this.onMouseOver,
5786                 'mouseout': this.onMouseOut,
5787                 scope: this
5788                 });
5789                 </code></pre>
5790      */
5791     addListener : function(eventName, fn, scope, o){
5792         if(typeof eventName == "object"){
5793             o = eventName;
5794             for(var e in o){
5795                 if(this.filterOptRe.test(e)){
5796                     continue;
5797                 }
5798                 if(typeof o[e] == "function"){
5799                     // shared options
5800                     this.addListener(e, o[e], o.scope,  o);
5801                 }else{
5802                     // individual options
5803                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5804                 }
5805             }
5806             return;
5807         }
5808         o = (!o || typeof o == "boolean") ? {} : o;
5809         eventName = eventName.toLowerCase();
5810         var ce = this.events[eventName] || true;
5811         if(typeof ce == "boolean"){
5812             ce = new Roo.util.Event(this, eventName);
5813             this.events[eventName] = ce;
5814         }
5815         ce.addListener(fn, scope, o);
5816     },
5817
5818     /**
5819      * Removes a listener
5820      * @param {String}   eventName     The type of event to listen for
5821      * @param {Function} handler        The handler to remove
5822      * @param {Object}   scope  (optional) The scope (this object) for the handler
5823      */
5824     removeListener : function(eventName, fn, scope){
5825         var ce = this.events[eventName.toLowerCase()];
5826         if(typeof ce == "object"){
5827             ce.removeListener(fn, scope);
5828         }
5829     },
5830
5831     /**
5832      * Removes all listeners for this object
5833      */
5834     purgeListeners : function(){
5835         for(var evt in this.events){
5836             if(typeof this.events[evt] == "object"){
5837                  this.events[evt].clearListeners();
5838             }
5839         }
5840     },
5841
5842     relayEvents : function(o, events){
5843         var createHandler = function(ename){
5844             return function(){
5845                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5846             };
5847         };
5848         for(var i = 0, len = events.length; i < len; i++){
5849             var ename = events[i];
5850             if(!this.events[ename]){ this.events[ename] = true; };
5851             o.on(ename, createHandler(ename), this);
5852         }
5853     },
5854
5855     /**
5856      * Used to define events on this Observable
5857      * @param {Object} object The object with the events defined
5858      */
5859     addEvents : function(o){
5860         if(!this.events){
5861             this.events = {};
5862         }
5863         Roo.applyIf(this.events, o);
5864     },
5865
5866     /**
5867      * Checks to see if this object has any listeners for a specified event
5868      * @param {String} eventName The name of the event to check for
5869      * @return {Boolean} True if the event is being listened for, else false
5870      */
5871     hasListener : function(eventName){
5872         var e = this.events[eventName];
5873         return typeof e == "object" && e.listeners.length > 0;
5874     }
5875 };
5876 /**
5877  * Appends an event handler to this element (shorthand for addListener)
5878  * @param {String}   eventName     The type of event to listen for
5879  * @param {Function} handler        The method the event invokes
5880  * @param {Object}   scope (optional) The scope in which to execute the handler
5881  * function. The handler function's "this" context.
5882  * @param {Object}   options  (optional)
5883  * @method
5884  */
5885 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5886 /**
5887  * Removes a listener (shorthand for removeListener)
5888  * @param {String}   eventName     The type of event to listen for
5889  * @param {Function} handler        The handler to remove
5890  * @param {Object}   scope  (optional) The scope (this object) for the handler
5891  * @method
5892  */
5893 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5894
5895 /**
5896  * Starts capture on the specified Observable. All events will be passed
5897  * to the supplied function with the event name + standard signature of the event
5898  * <b>before</b> the event is fired. If the supplied function returns false,
5899  * the event will not fire.
5900  * @param {Observable} o The Observable to capture
5901  * @param {Function} fn The function to call
5902  * @param {Object} scope (optional) The scope (this object) for the fn
5903  * @static
5904  */
5905 Roo.util.Observable.capture = function(o, fn, scope){
5906     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 };
5908
5909 /**
5910  * Removes <b>all</b> added captures from the Observable.
5911  * @param {Observable} o The Observable to release
5912  * @static
5913  */
5914 Roo.util.Observable.releaseCapture = function(o){
5915     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5916 };
5917
5918 (function(){
5919
5920     var createBuffered = function(h, o, scope){
5921         var task = new Roo.util.DelayedTask();
5922         return function(){
5923             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924         };
5925     };
5926
5927     var createSingle = function(h, e, fn, scope){
5928         return function(){
5929             e.removeListener(fn, scope);
5930             return h.apply(scope, arguments);
5931         };
5932     };
5933
5934     var createDelayed = function(h, o, scope){
5935         return function(){
5936             var args = Array.prototype.slice.call(arguments, 0);
5937             setTimeout(function(){
5938                 h.apply(scope, args);
5939             }, o.delay || 10);
5940         };
5941     };
5942
5943     Roo.util.Event = function(obj, name){
5944         this.name = name;
5945         this.obj = obj;
5946         this.listeners = [];
5947     };
5948
5949     Roo.util.Event.prototype = {
5950         addListener : function(fn, scope, options){
5951             var o = options || {};
5952             scope = scope || this.obj;
5953             if(!this.isListening(fn, scope)){
5954                 var l = {fn: fn, scope: scope, options: o};
5955                 var h = fn;
5956                 if(o.delay){
5957                     h = createDelayed(h, o, scope);
5958                 }
5959                 if(o.single){
5960                     h = createSingle(h, this, fn, scope);
5961                 }
5962                 if(o.buffer){
5963                     h = createBuffered(h, o, scope);
5964                 }
5965                 l.fireFn = h;
5966                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5967                     this.listeners.push(l);
5968                 }else{
5969                     this.listeners = this.listeners.slice(0);
5970                     this.listeners.push(l);
5971                 }
5972             }
5973         },
5974
5975         findListener : function(fn, scope){
5976             scope = scope || this.obj;
5977             var ls = this.listeners;
5978             for(var i = 0, len = ls.length; i < len; i++){
5979                 var l = ls[i];
5980                 if(l.fn == fn && l.scope == scope){
5981                     return i;
5982                 }
5983             }
5984             return -1;
5985         },
5986
5987         isListening : function(fn, scope){
5988             return this.findListener(fn, scope) != -1;
5989         },
5990
5991         removeListener : function(fn, scope){
5992             var index;
5993             if((index = this.findListener(fn, scope)) != -1){
5994                 if(!this.firing){
5995                     this.listeners.splice(index, 1);
5996                 }else{
5997                     this.listeners = this.listeners.slice(0);
5998                     this.listeners.splice(index, 1);
5999                 }
6000                 return true;
6001             }
6002             return false;
6003         },
6004
6005         clearListeners : function(){
6006             this.listeners = [];
6007         },
6008
6009         fire : function(){
6010             var ls = this.listeners, scope, len = ls.length;
6011             if(len > 0){
6012                 this.firing = true;
6013                 var args = Array.prototype.slice.call(arguments, 0);
6014                 for(var i = 0; i < len; i++){
6015                     var l = ls[i];
6016                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6017                         this.firing = false;
6018                         return false;
6019                     }
6020                 }
6021                 this.firing = false;
6022             }
6023             return true;
6024         }
6025     };
6026 })();/*
6027  * Based on:
6028  * Ext JS Library 1.1.1
6029  * Copyright(c) 2006-2007, Ext JS, LLC.
6030  *
6031  * Originally Released Under LGPL - original licence link has changed is not relivant.
6032  *
6033  * Fork - LGPL
6034  * <script type="text/javascript">
6035  */
6036
6037 /**
6038  * @class Roo.EventManager
6039  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6040  * several useful events directly.
6041  * See {@link Roo.EventObject} for more details on normalized event objects.
6042  * @singleton
6043  */
6044 Roo.EventManager = function(){
6045     var docReadyEvent, docReadyProcId, docReadyState = false;
6046     var resizeEvent, resizeTask, textEvent, textSize;
6047     var E = Roo.lib.Event;
6048     var D = Roo.lib.Dom;
6049
6050
6051     var fireDocReady = function(){
6052         if(!docReadyState){
6053             docReadyState = true;
6054             Roo.isReady = true;
6055             if(docReadyProcId){
6056                 clearInterval(docReadyProcId);
6057             }
6058             if(Roo.isGecko || Roo.isOpera) {
6059                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6060             }
6061             if(Roo.isIE){
6062                 var defer = document.getElementById("ie-deferred-loader");
6063                 if(defer){
6064                     defer.onreadystatechange = null;
6065                     defer.parentNode.removeChild(defer);
6066                 }
6067             }
6068             if(docReadyEvent){
6069                 docReadyEvent.fire();
6070                 docReadyEvent.clearListeners();
6071             }
6072         }
6073     };
6074     
6075     var initDocReady = function(){
6076         docReadyEvent = new Roo.util.Event();
6077         if(Roo.isGecko || Roo.isOpera) {
6078             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6079         }else if(Roo.isIE){
6080             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6081             var defer = document.getElementById("ie-deferred-loader");
6082             defer.onreadystatechange = function(){
6083                 if(this.readyState == "complete"){
6084                     fireDocReady();
6085                 }
6086             };
6087         }else if(Roo.isSafari){ 
6088             docReadyProcId = setInterval(function(){
6089                 var rs = document.readyState;
6090                 if(rs == "complete") {
6091                     fireDocReady();     
6092                  }
6093             }, 10);
6094         }
6095         // no matter what, make sure it fires on load
6096         E.on(window, "load", fireDocReady);
6097     };
6098
6099     var createBuffered = function(h, o){
6100         var task = new Roo.util.DelayedTask(h);
6101         return function(e){
6102             // create new event object impl so new events don't wipe out properties
6103             e = new Roo.EventObjectImpl(e);
6104             task.delay(o.buffer, h, null, [e]);
6105         };
6106     };
6107
6108     var createSingle = function(h, el, ename, fn){
6109         return function(e){
6110             Roo.EventManager.removeListener(el, ename, fn);
6111             h(e);
6112         };
6113     };
6114
6115     var createDelayed = function(h, o){
6116         return function(e){
6117             // create new event object impl so new events don't wipe out properties
6118             e = new Roo.EventObjectImpl(e);
6119             setTimeout(function(){
6120                 h(e);
6121             }, o.delay || 10);
6122         };
6123     };
6124
6125     var listen = function(element, ename, opt, fn, scope){
6126         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6127         fn = fn || o.fn; scope = scope || o.scope;
6128         var el = Roo.getDom(element);
6129         if(!el){
6130             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6131         }
6132         var h = function(e){
6133             e = Roo.EventObject.setEvent(e);
6134             var t;
6135             if(o.delegate){
6136                 t = e.getTarget(o.delegate, el);
6137                 if(!t){
6138                     return;
6139                 }
6140             }else{
6141                 t = e.target;
6142             }
6143             if(o.stopEvent === true){
6144                 e.stopEvent();
6145             }
6146             if(o.preventDefault === true){
6147                e.preventDefault();
6148             }
6149             if(o.stopPropagation === true){
6150                 e.stopPropagation();
6151             }
6152
6153             if(o.normalized === false){
6154                 e = e.browserEvent;
6155             }
6156
6157             fn.call(scope || el, e, t, o);
6158         };
6159         if(o.delay){
6160             h = createDelayed(h, o);
6161         }
6162         if(o.single){
6163             h = createSingle(h, el, ename, fn);
6164         }
6165         if(o.buffer){
6166             h = createBuffered(h, o);
6167         }
6168         fn._handlers = fn._handlers || [];
6169         fn._handlers.push([Roo.id(el), ename, h]);
6170
6171         E.on(el, ename, h);
6172         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6173             el.addEventListener("DOMMouseScroll", h, false);
6174             E.on(window, 'unload', function(){
6175                 el.removeEventListener("DOMMouseScroll", h, false);
6176             });
6177         }
6178         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6179             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6180         }
6181         return h;
6182     };
6183
6184     var stopListening = function(el, ename, fn){
6185         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6186         if(hds){
6187             for(var i = 0, len = hds.length; i < len; i++){
6188                 var h = hds[i];
6189                 if(h[0] == id && h[1] == ename){
6190                     hd = h[2];
6191                     hds.splice(i, 1);
6192                     break;
6193                 }
6194             }
6195         }
6196         E.un(el, ename, hd);
6197         el = Roo.getDom(el);
6198         if(ename == "mousewheel" && el.addEventListener){
6199             el.removeEventListener("DOMMouseScroll", hd, false);
6200         }
6201         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6202             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203         }
6204     };
6205
6206     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6207     
6208     var pub = {
6209         
6210         
6211         /** 
6212          * Fix for doc tools
6213          * @scope Roo.EventManager
6214          */
6215         
6216         
6217         /** 
6218          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6219          * object with a Roo.EventObject
6220          * @param {Function} fn        The method the event invokes
6221          * @param {Object}   scope    An object that becomes the scope of the handler
6222          * @param {boolean}  override If true, the obj passed in becomes
6223          *                             the execution scope of the listener
6224          * @return {Function} The wrapped function
6225          * @deprecated
6226          */
6227         wrap : function(fn, scope, override){
6228             return function(e){
6229                 Roo.EventObject.setEvent(e);
6230                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6231             };
6232         },
6233         
6234         /**
6235      * Appends an event handler to an element (shorthand for addListener)
6236      * @param {String/HTMLElement}   element        The html element or id to assign the
6237      * @param {String}   eventName The type of event to listen for
6238      * @param {Function} handler The method the event invokes
6239      * @param {Object}   scope (optional) The scope in which to execute the handler
6240      * function. The handler function's "this" context.
6241      * @param {Object}   options (optional) An object containing handler configuration
6242      * properties. This may contain any of the following properties:<ul>
6243      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6244      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6245      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6246      * <li>preventDefault {Boolean} True to prevent the default action</li>
6247      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6248      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6249      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6250      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6251      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6252      * by the specified number of milliseconds. If the event fires again within that time, the original
6253      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6254      * </ul><br>
6255      * <p>
6256      * <b>Combining Options</b><br>
6257      * Using the options argument, it is possible to combine different types of listeners:<br>
6258      * <br>
6259      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6260      * Code:<pre><code>
6261 el.on('click', this.onClick, this, {
6262     single: true,
6263     delay: 100,
6264     stopEvent : true,
6265     forumId: 4
6266 });</code></pre>
6267      * <p>
6268      * <b>Attaching multiple handlers in 1 call</b><br>
6269       * The method also allows for a single argument to be passed which is a config object containing properties
6270      * which specify multiple handlers.
6271      * <p>
6272      * Code:<pre><code>
6273 el.on({
6274     'click' : {
6275         fn: this.onClick
6276         scope: this,
6277         delay: 100
6278     },
6279     'mouseover' : {
6280         fn: this.onMouseOver
6281         scope: this
6282     },
6283     'mouseout' : {
6284         fn: this.onMouseOut
6285         scope: this
6286     }
6287 });</code></pre>
6288      * <p>
6289      * Or a shorthand syntax:<br>
6290      * Code:<pre><code>
6291 el.on({
6292     'click' : this.onClick,
6293     'mouseover' : this.onMouseOver,
6294     'mouseout' : this.onMouseOut
6295     scope: this
6296 });</code></pre>
6297      */
6298         addListener : function(element, eventName, fn, scope, options){
6299             if(typeof eventName == "object"){
6300                 var o = eventName;
6301                 for(var e in o){
6302                     if(propRe.test(e)){
6303                         continue;
6304                     }
6305                     if(typeof o[e] == "function"){
6306                         // shared options
6307                         listen(element, e, o, o[e], o.scope);
6308                     }else{
6309                         // individual options
6310                         listen(element, e, o[e]);
6311                     }
6312                 }
6313                 return;
6314             }
6315             return listen(element, eventName, options, fn, scope);
6316         },
6317         
6318         /**
6319          * Removes an event handler
6320          *
6321          * @param {String/HTMLElement}   element        The id or html element to remove the 
6322          *                             event from
6323          * @param {String}   eventName     The type of event
6324          * @param {Function} fn
6325          * @return {Boolean} True if a listener was actually removed
6326          */
6327         removeListener : function(element, eventName, fn){
6328             return stopListening(element, eventName, fn);
6329         },
6330         
6331         /**
6332          * Fires when the document is ready (before onload and before images are loaded). Can be 
6333          * accessed shorthanded Roo.onReady().
6334          * @param {Function} fn        The method the event invokes
6335          * @param {Object}   scope    An  object that becomes the scope of the handler
6336          * @param {boolean}  options
6337          */
6338         onDocumentReady : function(fn, scope, options){
6339             if(docReadyState){ // if it already fired
6340                 docReadyEvent.addListener(fn, scope, options);
6341                 docReadyEvent.fire();
6342                 docReadyEvent.clearListeners();
6343                 return;
6344             }
6345             if(!docReadyEvent){
6346                 initDocReady();
6347             }
6348             docReadyEvent.addListener(fn, scope, options);
6349         },
6350         
6351         /**
6352          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6353          * @param {Function} fn        The method the event invokes
6354          * @param {Object}   scope    An object that becomes the scope of the handler
6355          * @param {boolean}  options
6356          */
6357         onWindowResize : function(fn, scope, options){
6358             if(!resizeEvent){
6359                 resizeEvent = new Roo.util.Event();
6360                 resizeTask = new Roo.util.DelayedTask(function(){
6361                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6362                 });
6363                 E.on(window, "resize", function(){
6364                     if(Roo.isIE){
6365                         resizeTask.delay(50);
6366                     }else{
6367                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368                     }
6369                 });
6370             }
6371             resizeEvent.addListener(fn, scope, options);
6372         },
6373
6374         /**
6375          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6376          * @param {Function} fn        The method the event invokes
6377          * @param {Object}   scope    An object that becomes the scope of the handler
6378          * @param {boolean}  options
6379          */
6380         onTextResize : function(fn, scope, options){
6381             if(!textEvent){
6382                 textEvent = new Roo.util.Event();
6383                 var textEl = new Roo.Element(document.createElement('div'));
6384                 textEl.dom.className = 'x-text-resize';
6385                 textEl.dom.innerHTML = 'X';
6386                 textEl.appendTo(document.body);
6387                 textSize = textEl.dom.offsetHeight;
6388                 setInterval(function(){
6389                     if(textEl.dom.offsetHeight != textSize){
6390                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6391                     }
6392                 }, this.textResizeInterval);
6393             }
6394             textEvent.addListener(fn, scope, options);
6395         },
6396
6397         /**
6398          * Removes the passed window resize listener.
6399          * @param {Function} fn        The method the event invokes
6400          * @param {Object}   scope    The scope of handler
6401          */
6402         removeResizeListener : function(fn, scope){
6403             if(resizeEvent){
6404                 resizeEvent.removeListener(fn, scope);
6405             }
6406         },
6407
6408         // private
6409         fireResize : function(){
6410             if(resizeEvent){
6411                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412             }   
6413         },
6414         /**
6415          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416          */
6417         ieDeferSrc : false,
6418         /**
6419          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6420          */
6421         textResizeInterval : 50
6422     };
6423     
6424     /**
6425      * Fix for doc tools
6426      * @scopeAlias pub=Roo.EventManager
6427      */
6428     
6429      /**
6430      * Appends an event handler to an element (shorthand for addListener)
6431      * @param {String/HTMLElement}   element        The html element or id to assign the
6432      * @param {String}   eventName The type of event to listen for
6433      * @param {Function} handler The method the event invokes
6434      * @param {Object}   scope (optional) The scope in which to execute the handler
6435      * function. The handler function's "this" context.
6436      * @param {Object}   options (optional) An object containing handler configuration
6437      * properties. This may contain any of the following properties:<ul>
6438      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6439      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6440      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6441      * <li>preventDefault {Boolean} True to prevent the default action</li>
6442      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6443      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6444      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6445      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6446      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6447      * by the specified number of milliseconds. If the event fires again within that time, the original
6448      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6449      * </ul><br>
6450      * <p>
6451      * <b>Combining Options</b><br>
6452      * Using the options argument, it is possible to combine different types of listeners:<br>
6453      * <br>
6454      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6455      * Code:<pre><code>
6456 el.on('click', this.onClick, this, {
6457     single: true,
6458     delay: 100,
6459     stopEvent : true,
6460     forumId: 4
6461 });</code></pre>
6462      * <p>
6463      * <b>Attaching multiple handlers in 1 call</b><br>
6464       * The method also allows for a single argument to be passed which is a config object containing properties
6465      * which specify multiple handlers.
6466      * <p>
6467      * Code:<pre><code>
6468 el.on({
6469     'click' : {
6470         fn: this.onClick
6471         scope: this,
6472         delay: 100
6473     },
6474     'mouseover' : {
6475         fn: this.onMouseOver
6476         scope: this
6477     },
6478     'mouseout' : {
6479         fn: this.onMouseOut
6480         scope: this
6481     }
6482 });</code></pre>
6483      * <p>
6484      * Or a shorthand syntax:<br>
6485      * Code:<pre><code>
6486 el.on({
6487     'click' : this.onClick,
6488     'mouseover' : this.onMouseOver,
6489     'mouseout' : this.onMouseOut
6490     scope: this
6491 });</code></pre>
6492      */
6493     pub.on = pub.addListener;
6494     pub.un = pub.removeListener;
6495
6496     pub.stoppedMouseDownEvent = new Roo.util.Event();
6497     return pub;
6498 }();
6499 /**
6500   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6501   * @param {Function} fn        The method the event invokes
6502   * @param {Object}   scope    An  object that becomes the scope of the handler
6503   * @param {boolean}  override If true, the obj passed in becomes
6504   *                             the execution scope of the listener
6505   * @member Roo
6506   * @method onReady
6507  */
6508 Roo.onReady = Roo.EventManager.onDocumentReady;
6509
6510 Roo.onReady(function(){
6511     var bd = Roo.get(document.body);
6512     if(!bd){ return; }
6513
6514     var cls = [
6515             Roo.isIE ? "roo-ie"
6516             : Roo.isGecko ? "roo-gecko"
6517             : Roo.isOpera ? "roo-opera"
6518             : Roo.isSafari ? "roo-safari" : ""];
6519
6520     if(Roo.isMac){
6521         cls.push("roo-mac");
6522     }
6523     if(Roo.isLinux){
6524         cls.push("roo-linux");
6525     }
6526     if(Roo.isBorderBox){
6527         cls.push('roo-border-box');
6528     }
6529     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6530         var p = bd.dom.parentNode;
6531         if(p){
6532             p.className += ' roo-strict';
6533         }
6534     }
6535     bd.addClass(cls.join(' '));
6536 });
6537
6538 /**
6539  * @class Roo.EventObject
6540  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6541  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6542  * Example:
6543  * <pre><code>
6544  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6545     e.preventDefault();
6546     var target = e.getTarget();
6547     ...
6548  }
6549  var myDiv = Roo.get("myDiv");
6550  myDiv.on("click", handleClick);
6551  //or
6552  Roo.EventManager.on("myDiv", 'click', handleClick);
6553  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554  </code></pre>
6555  * @singleton
6556  */
6557 Roo.EventObject = function(){
6558     
6559     var E = Roo.lib.Event;
6560     
6561     // safari keypress events for special keys return bad keycodes
6562     var safariKeys = {
6563         63234 : 37, // left
6564         63235 : 39, // right
6565         63232 : 38, // up
6566         63233 : 40, // down
6567         63276 : 33, // page up
6568         63277 : 34, // page down
6569         63272 : 46, // delete
6570         63273 : 36, // home
6571         63275 : 35  // end
6572     };
6573
6574     // normalize button clicks
6575     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6576                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6577
6578     Roo.EventObjectImpl = function(e){
6579         if(e){
6580             this.setEvent(e.browserEvent || e);
6581         }
6582     };
6583     Roo.EventObjectImpl.prototype = {
6584         /**
6585          * Used to fix doc tools.
6586          * @scope Roo.EventObject.prototype
6587          */
6588             
6589
6590         
6591         
6592         /** The normal browser event */
6593         browserEvent : null,
6594         /** The button pressed in a mouse event */
6595         button : -1,
6596         /** True if the shift key was down during the event */
6597         shiftKey : false,
6598         /** True if the control key was down during the event */
6599         ctrlKey : false,
6600         /** True if the alt key was down during the event */
6601         altKey : false,
6602
6603         /** Key constant 
6604         * @type Number */
6605         BACKSPACE : 8,
6606         /** Key constant 
6607         * @type Number */
6608         TAB : 9,
6609         /** Key constant 
6610         * @type Number */
6611         RETURN : 13,
6612         /** Key constant 
6613         * @type Number */
6614         ENTER : 13,
6615         /** Key constant 
6616         * @type Number */
6617         SHIFT : 16,
6618         /** Key constant 
6619         * @type Number */
6620         CONTROL : 17,
6621         /** Key constant 
6622         * @type Number */
6623         ESC : 27,
6624         /** Key constant 
6625         * @type Number */
6626         SPACE : 32,
6627         /** Key constant 
6628         * @type Number */
6629         PAGEUP : 33,
6630         /** Key constant 
6631         * @type Number */
6632         PAGEDOWN : 34,
6633         /** Key constant 
6634         * @type Number */
6635         END : 35,
6636         /** Key constant 
6637         * @type Number */
6638         HOME : 36,
6639         /** Key constant 
6640         * @type Number */
6641         LEFT : 37,
6642         /** Key constant 
6643         * @type Number */
6644         UP : 38,
6645         /** Key constant 
6646         * @type Number */
6647         RIGHT : 39,
6648         /** Key constant 
6649         * @type Number */
6650         DOWN : 40,
6651         /** Key constant 
6652         * @type Number */
6653         DELETE : 46,
6654         /** Key constant 
6655         * @type Number */
6656         F5 : 116,
6657
6658            /** @private */
6659         setEvent : function(e){
6660             if(e == this || (e && e.browserEvent)){ // already wrapped
6661                 return e;
6662             }
6663             this.browserEvent = e;
6664             if(e){
6665                 // normalize buttons
6666                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6667                 if(e.type == 'click' && this.button == -1){
6668                     this.button = 0;
6669                 }
6670                 this.type = e.type;
6671                 this.shiftKey = e.shiftKey;
6672                 // mac metaKey behaves like ctrlKey
6673                 this.ctrlKey = e.ctrlKey || e.metaKey;
6674                 this.altKey = e.altKey;
6675                 // in getKey these will be normalized for the mac
6676                 this.keyCode = e.keyCode;
6677                 // keyup warnings on firefox.
6678                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6679                 // cache the target for the delayed and or buffered events
6680                 this.target = E.getTarget(e);
6681                 // same for XY
6682                 this.xy = E.getXY(e);
6683             }else{
6684                 this.button = -1;
6685                 this.shiftKey = false;
6686                 this.ctrlKey = false;
6687                 this.altKey = false;
6688                 this.keyCode = 0;
6689                 this.charCode =0;
6690                 this.target = null;
6691                 this.xy = [0, 0];
6692             }
6693             return this;
6694         },
6695
6696         /**
6697          * Stop the event (preventDefault and stopPropagation)
6698          */
6699         stopEvent : function(){
6700             if(this.browserEvent){
6701                 if(this.browserEvent.type == 'mousedown'){
6702                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6703                 }
6704                 E.stopEvent(this.browserEvent);
6705             }
6706         },
6707
6708         /**
6709          * Prevents the browsers default handling of the event.
6710          */
6711         preventDefault : function(){
6712             if(this.browserEvent){
6713                 E.preventDefault(this.browserEvent);
6714             }
6715         },
6716
6717         /** @private */
6718         isNavKeyPress : function(){
6719             var k = this.keyCode;
6720             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6721             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6722         },
6723
6724         isSpecialKey : function(){
6725             var k = this.keyCode;
6726             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6727             (k == 16) || (k == 17) ||
6728             (k >= 18 && k <= 20) ||
6729             (k >= 33 && k <= 35) ||
6730             (k >= 36 && k <= 39) ||
6731             (k >= 44 && k <= 45);
6732         },
6733         /**
6734          * Cancels bubbling of the event.
6735          */
6736         stopPropagation : function(){
6737             if(this.browserEvent){
6738                 if(this.type == 'mousedown'){
6739                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6740                 }
6741                 E.stopPropagation(this.browserEvent);
6742             }
6743         },
6744
6745         /**
6746          * Gets the key code for the event.
6747          * @return {Number}
6748          */
6749         getCharCode : function(){
6750             return this.charCode || this.keyCode;
6751         },
6752
6753         /**
6754          * Returns a normalized keyCode for the event.
6755          * @return {Number} The key code
6756          */
6757         getKey : function(){
6758             var k = this.keyCode || this.charCode;
6759             return Roo.isSafari ? (safariKeys[k] || k) : k;
6760         },
6761
6762         /**
6763          * Gets the x coordinate of the event.
6764          * @return {Number}
6765          */
6766         getPageX : function(){
6767             return this.xy[0];
6768         },
6769
6770         /**
6771          * Gets the y coordinate of the event.
6772          * @return {Number}
6773          */
6774         getPageY : function(){
6775             return this.xy[1];
6776         },
6777
6778         /**
6779          * Gets the time of the event.
6780          * @return {Number}
6781          */
6782         getTime : function(){
6783             if(this.browserEvent){
6784                 return E.getTime(this.browserEvent);
6785             }
6786             return null;
6787         },
6788
6789         /**
6790          * Gets the page coordinates of the event.
6791          * @return {Array} The xy values like [x, y]
6792          */
6793         getXY : function(){
6794             return this.xy;
6795         },
6796
6797         /**
6798          * Gets the target for the event.
6799          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6800          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6801                 search as a number or element (defaults to 10 || document.body)
6802          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6803          * @return {HTMLelement}
6804          */
6805         getTarget : function(selector, maxDepth, returnEl){
6806             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6807         },
6808         /**
6809          * Gets the related target.
6810          * @return {HTMLElement}
6811          */
6812         getRelatedTarget : function(){
6813             if(this.browserEvent){
6814                 return E.getRelatedTarget(this.browserEvent);
6815             }
6816             return null;
6817         },
6818
6819         /**
6820          * Normalizes mouse wheel delta across browsers
6821          * @return {Number} The delta
6822          */
6823         getWheelDelta : function(){
6824             var e = this.browserEvent;
6825             var delta = 0;
6826             if(e.wheelDelta){ /* IE/Opera. */
6827                 delta = e.wheelDelta/120;
6828             }else if(e.detail){ /* Mozilla case. */
6829                 delta = -e.detail/3;
6830             }
6831             return delta;
6832         },
6833
6834         /**
6835          * Returns true if the control, meta, shift or alt key was pressed during this event.
6836          * @return {Boolean}
6837          */
6838         hasModifier : function(){
6839             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840         },
6841
6842         /**
6843          * Returns true if the target of this event equals el or is a child of el
6844          * @param {String/HTMLElement/Element} el
6845          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6846          * @return {Boolean}
6847          */
6848         within : function(el, related){
6849             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6850             return t && Roo.fly(el).contains(t);
6851         },
6852
6853         getPoint : function(){
6854             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855         }
6856     };
6857
6858     return new Roo.EventObjectImpl();
6859 }();
6860             
6861     /*
6862  * Based on:
6863  * Ext JS Library 1.1.1
6864  * Copyright(c) 2006-2007, Ext JS, LLC.
6865  *
6866  * Originally Released Under LGPL - original licence link has changed is not relivant.
6867  *
6868  * Fork - LGPL
6869  * <script type="text/javascript">
6870  */
6871
6872  
6873 // was in Composite Element!??!?!
6874  
6875 (function(){
6876     var D = Roo.lib.Dom;
6877     var E = Roo.lib.Event;
6878     var A = Roo.lib.Anim;
6879
6880     // local style camelizing for speed
6881     var propCache = {};
6882     var camelRe = /(-[a-z])/gi;
6883     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6884     var view = document.defaultView;
6885
6886 /**
6887  * @class Roo.Element
6888  * Represents an Element in the DOM.<br><br>
6889  * Usage:<br>
6890 <pre><code>
6891 var el = Roo.get("my-div");
6892
6893 // or with getEl
6894 var el = getEl("my-div");
6895
6896 // or with a DOM element
6897 var el = Roo.get(myDivElement);
6898 </code></pre>
6899  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6900  * each call instead of constructing a new one.<br><br>
6901  * <b>Animations</b><br />
6902  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6903  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6904 <pre>
6905 Option    Default   Description
6906 --------- --------  ---------------------------------------------
6907 duration  .35       The duration of the animation in seconds
6908 easing    easeOut   The YUI easing method
6909 callback  none      A function to execute when the anim completes
6910 scope     this      The scope (this) of the callback function
6911 </pre>
6912 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6913 * manipulate the animation. Here's an example:
6914 <pre><code>
6915 var el = Roo.get("my-div");
6916
6917 // no animation
6918 el.setWidth(100);
6919
6920 // default animation
6921 el.setWidth(100, true);
6922
6923 // animation with some options set
6924 el.setWidth(100, {
6925     duration: 1,
6926     callback: this.foo,
6927     scope: this
6928 });
6929
6930 // using the "anim" property to get the Anim object
6931 var opt = {
6932     duration: 1,
6933     callback: this.foo,
6934     scope: this
6935 };
6936 el.setWidth(100, opt);
6937 ...
6938 if(opt.anim.isAnimated()){
6939     opt.anim.stop();
6940 }
6941 </code></pre>
6942 * <b> Composite (Collections of) Elements</b><br />
6943  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6944  * @constructor Create a new Element directly.
6945  * @param {String/HTMLElement} element
6946  * @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).
6947  */
6948     Roo.Element = function(element, forceNew){
6949         var dom = typeof element == "string" ?
6950                 document.getElementById(element) : element;
6951         if(!dom){ // invalid id/element
6952             return null;
6953         }
6954         var id = dom.id;
6955         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6956             return Roo.Element.cache[id];
6957         }
6958
6959         /**
6960          * The DOM element
6961          * @type HTMLElement
6962          */
6963         this.dom = dom;
6964
6965         /**
6966          * The DOM element ID
6967          * @type String
6968          */
6969         this.id = id || Roo.id(dom);
6970     };
6971
6972     var El = Roo.Element;
6973
6974     El.prototype = {
6975         /**
6976          * The element's default display mode  (defaults to "")
6977          * @type String
6978          */
6979         originalDisplay : "",
6980
6981         visibilityMode : 1,
6982         /**
6983          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6984          * @type String
6985          */
6986         defaultUnit : "px",
6987         /**
6988          * Sets the element's visibility mode. When setVisible() is called it
6989          * will use this to determine whether to set the visibility or the display property.
6990          * @param visMode Element.VISIBILITY or Element.DISPLAY
6991          * @return {Roo.Element} this
6992          */
6993         setVisibilityMode : function(visMode){
6994             this.visibilityMode = visMode;
6995             return this;
6996         },
6997         /**
6998          * Convenience method for setVisibilityMode(Element.DISPLAY)
6999          * @param {String} display (optional) What to set display to when visible
7000          * @return {Roo.Element} this
7001          */
7002         enableDisplayMode : function(display){
7003             this.setVisibilityMode(El.DISPLAY);
7004             if(typeof display != "undefined") this.originalDisplay = display;
7005             return this;
7006         },
7007
7008         /**
7009          * 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)
7010          * @param {String} selector The simple selector to test
7011          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7012                 search as a number or element (defaults to 10 || document.body)
7013          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7014          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7015          */
7016         findParent : function(simpleSelector, maxDepth, returnEl){
7017             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7018             maxDepth = maxDepth || 50;
7019             if(typeof maxDepth != "number"){
7020                 stopEl = Roo.getDom(maxDepth);
7021                 maxDepth = 10;
7022             }
7023             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7024                 if(dq.is(p, simpleSelector)){
7025                     return returnEl ? Roo.get(p) : p;
7026                 }
7027                 depth++;
7028                 p = p.parentNode;
7029             }
7030             return null;
7031         },
7032
7033
7034         /**
7035          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7036          * @param {String} selector The simple selector to test
7037          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7038                 search as a number or element (defaults to 10 || document.body)
7039          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7040          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7041          */
7042         findParentNode : function(simpleSelector, maxDepth, returnEl){
7043             var p = Roo.fly(this.dom.parentNode, '_internal');
7044             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045         },
7046
7047         /**
7048          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7049          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7050          * @param {String} selector The simple selector to test
7051          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7052                 search as a number or element (defaults to 10 || document.body)
7053          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7054          */
7055         up : function(simpleSelector, maxDepth){
7056             return this.findParentNode(simpleSelector, maxDepth, true);
7057         },
7058
7059
7060
7061         /**
7062          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7063          * @param {String} selector The simple selector to test
7064          * @return {Boolean} True if this element matches the selector, else false
7065          */
7066         is : function(simpleSelector){
7067             return Roo.DomQuery.is(this.dom, simpleSelector);
7068         },
7069
7070         /**
7071          * Perform animation on this element.
7072          * @param {Object} args The YUI animation control args
7073          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7074          * @param {Function} onComplete (optional) Function to call when animation completes
7075          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7076          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7077          * @return {Roo.Element} this
7078          */
7079         animate : function(args, duration, onComplete, easing, animType){
7080             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7081             return this;
7082         },
7083
7084         /*
7085          * @private Internal animation call
7086          */
7087         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7088             animType = animType || 'run';
7089             opt = opt || {};
7090             var anim = Roo.lib.Anim[animType](
7091                 this.dom, args,
7092                 (opt.duration || defaultDur) || .35,
7093                 (opt.easing || defaultEase) || 'easeOut',
7094                 function(){
7095                     Roo.callback(cb, this);
7096                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7097                 },
7098                 this
7099             );
7100             opt.anim = anim;
7101             return anim;
7102         },
7103
7104         // private legacy anim prep
7105         preanim : function(a, i){
7106             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107         },
7108
7109         /**
7110          * Removes worthless text nodes
7111          * @param {Boolean} forceReclean (optional) By default the element
7112          * keeps track if it has been cleaned already so
7113          * you can call this over and over. However, if you update the element and
7114          * need to force a reclean, you can pass true.
7115          */
7116         clean : function(forceReclean){
7117             if(this.isCleaned && forceReclean !== true){
7118                 return this;
7119             }
7120             var ns = /\S/;
7121             var d = this.dom, n = d.firstChild, ni = -1;
7122             while(n){
7123                 var nx = n.nextSibling;
7124                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7125                     d.removeChild(n);
7126                 }else{
7127                     n.nodeIndex = ++ni;
7128                 }
7129                 n = nx;
7130             }
7131             this.isCleaned = true;
7132             return this;
7133         },
7134
7135         // private
7136         calcOffsetsTo : function(el){
7137             el = Roo.get(el);
7138             var d = el.dom;
7139             var restorePos = false;
7140             if(el.getStyle('position') == 'static'){
7141                 el.position('relative');
7142                 restorePos = true;
7143             }
7144             var x = 0, y =0;
7145             var op = this.dom;
7146             while(op && op != d && op.tagName != 'HTML'){
7147                 x+= op.offsetLeft;
7148                 y+= op.offsetTop;
7149                 op = op.offsetParent;
7150             }
7151             if(restorePos){
7152                 el.position('static');
7153             }
7154             return [x, y];
7155         },
7156
7157         /**
7158          * Scrolls this element into view within the passed container.
7159          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7160          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7161          * @return {Roo.Element} this
7162          */
7163         scrollIntoView : function(container, hscroll){
7164             var c = Roo.getDom(container) || document.body;
7165             var el = this.dom;
7166
7167             var o = this.calcOffsetsTo(c),
7168                 l = o[0],
7169                 t = o[1],
7170                 b = t+el.offsetHeight,
7171                 r = l+el.offsetWidth;
7172
7173             var ch = c.clientHeight;
7174             var ct = parseInt(c.scrollTop, 10);
7175             var cl = parseInt(c.scrollLeft, 10);
7176             var cb = ct + ch;
7177             var cr = cl + c.clientWidth;
7178
7179             if(t < ct){
7180                 c.scrollTop = t;
7181             }else if(b > cb){
7182                 c.scrollTop = b-ch;
7183             }
7184
7185             if(hscroll !== false){
7186                 if(l < cl){
7187                     c.scrollLeft = l;
7188                 }else if(r > cr){
7189                     c.scrollLeft = r-c.clientWidth;
7190                 }
7191             }
7192             return this;
7193         },
7194
7195         // private
7196         scrollChildIntoView : function(child, hscroll){
7197             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198         },
7199
7200         /**
7201          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7202          * the new height may not be available immediately.
7203          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7204          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7205          * @param {Function} onComplete (optional) Function to call when animation completes
7206          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7207          * @return {Roo.Element} this
7208          */
7209         autoHeight : function(animate, duration, onComplete, easing){
7210             var oldHeight = this.getHeight();
7211             this.clip();
7212             this.setHeight(1); // force clipping
7213             setTimeout(function(){
7214                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7215                 if(!animate){
7216                     this.setHeight(height);
7217                     this.unclip();
7218                     if(typeof onComplete == "function"){
7219                         onComplete();
7220                     }
7221                 }else{
7222                     this.setHeight(oldHeight); // restore original height
7223                     this.setHeight(height, animate, duration, function(){
7224                         this.unclip();
7225                         if(typeof onComplete == "function") onComplete();
7226                     }.createDelegate(this), easing);
7227                 }
7228             }.createDelegate(this), 0);
7229             return this;
7230         },
7231
7232         /**
7233          * Returns true if this element is an ancestor of the passed element
7234          * @param {HTMLElement/String} el The element to check
7235          * @return {Boolean} True if this element is an ancestor of el, else false
7236          */
7237         contains : function(el){
7238             if(!el){return false;}
7239             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240         },
7241
7242         /**
7243          * Checks whether the element is currently visible using both visibility and display properties.
7244          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7245          * @return {Boolean} True if the element is currently visible, else false
7246          */
7247         isVisible : function(deep) {
7248             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7249             if(deep !== true || !vis){
7250                 return vis;
7251             }
7252             var p = this.dom.parentNode;
7253             while(p && p.tagName.toLowerCase() != "body"){
7254                 if(!Roo.fly(p, '_isVisible').isVisible()){
7255                     return false;
7256                 }
7257                 p = p.parentNode;
7258             }
7259             return true;
7260         },
7261
7262         /**
7263          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7264          * @param {String} selector The CSS selector
7265          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7266          * @return {CompositeElement/CompositeElementLite} The composite element
7267          */
7268         select : function(selector, unique){
7269             return El.select(selector, unique, this.dom);
7270         },
7271
7272         /**
7273          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7274          * @param {String} selector The CSS selector
7275          * @return {Array} An array of the matched nodes
7276          */
7277         query : function(selector, unique){
7278             return Roo.DomQuery.select(selector, this.dom);
7279         },
7280
7281         /**
7282          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7283          * @param {String} selector The CSS selector
7284          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7285          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7286          */
7287         child : function(selector, returnDom){
7288             var n = Roo.DomQuery.selectNode(selector, this.dom);
7289             return returnDom ? n : Roo.get(n);
7290         },
7291
7292         /**
7293          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7294          * @param {String} selector The CSS selector
7295          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7296          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7297          */
7298         down : function(selector, returnDom){
7299             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7300             return returnDom ? n : Roo.get(n);
7301         },
7302
7303         /**
7304          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7305          * @param {String} group The group the DD object is member of
7306          * @param {Object} config The DD config object
7307          * @param {Object} overrides An object containing methods to override/implement on the DD object
7308          * @return {Roo.dd.DD} The DD object
7309          */
7310         initDD : function(group, config, overrides){
7311             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7312             return Roo.apply(dd, overrides);
7313         },
7314
7315         /**
7316          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7317          * @param {String} group The group the DDProxy object is member of
7318          * @param {Object} config The DDProxy config object
7319          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7320          * @return {Roo.dd.DDProxy} The DDProxy object
7321          */
7322         initDDProxy : function(group, config, overrides){
7323             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7324             return Roo.apply(dd, overrides);
7325         },
7326
7327         /**
7328          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7329          * @param {String} group The group the DDTarget object is member of
7330          * @param {Object} config The DDTarget config object
7331          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7332          * @return {Roo.dd.DDTarget} The DDTarget object
7333          */
7334         initDDTarget : function(group, config, overrides){
7335             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7336             return Roo.apply(dd, overrides);
7337         },
7338
7339         /**
7340          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7341          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7342          * @param {Boolean} visible Whether the element is visible
7343          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7344          * @return {Roo.Element} this
7345          */
7346          setVisible : function(visible, animate){
7347             if(!animate || !A){
7348                 if(this.visibilityMode == El.DISPLAY){
7349                     this.setDisplayed(visible);
7350                 }else{
7351                     this.fixDisplay();
7352                     this.dom.style.visibility = visible ? "visible" : "hidden";
7353                 }
7354             }else{
7355                 // closure for composites
7356                 var dom = this.dom;
7357                 var visMode = this.visibilityMode;
7358                 if(visible){
7359                     this.setOpacity(.01);
7360                     this.setVisible(true);
7361                 }
7362                 this.anim({opacity: { to: (visible?1:0) }},
7363                       this.preanim(arguments, 1),
7364                       null, .35, 'easeIn', function(){
7365                          if(!visible){
7366                              if(visMode == El.DISPLAY){
7367                                  dom.style.display = "none";
7368                              }else{
7369                                  dom.style.visibility = "hidden";
7370                              }
7371                              Roo.get(dom).setOpacity(1);
7372                          }
7373                      });
7374             }
7375             return this;
7376         },
7377
7378         /**
7379          * Returns true if display is not "none"
7380          * @return {Boolean}
7381          */
7382         isDisplayed : function() {
7383             return this.getStyle("display") != "none";
7384         },
7385
7386         /**
7387          * Toggles the element's visibility or display, depending on visibility mode.
7388          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7389          * @return {Roo.Element} this
7390          */
7391         toggle : function(animate){
7392             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7393             return this;
7394         },
7395
7396         /**
7397          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7398          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7399          * @return {Roo.Element} this
7400          */
7401         setDisplayed : function(value) {
7402             if(typeof value == "boolean"){
7403                value = value ? this.originalDisplay : "none";
7404             }
7405             this.setStyle("display", value);
7406             return this;
7407         },
7408
7409         /**
7410          * Tries to focus the element. Any exceptions are caught and ignored.
7411          * @return {Roo.Element} this
7412          */
7413         focus : function() {
7414             try{
7415                 this.dom.focus();
7416             }catch(e){}
7417             return this;
7418         },
7419
7420         /**
7421          * Tries to blur the element. Any exceptions are caught and ignored.
7422          * @return {Roo.Element} this
7423          */
7424         blur : function() {
7425             try{
7426                 this.dom.blur();
7427             }catch(e){}
7428             return this;
7429         },
7430
7431         /**
7432          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7433          * @param {String/Array} className The CSS class to add, or an array of classes
7434          * @return {Roo.Element} this
7435          */
7436         addClass : function(className){
7437             if(className instanceof Array){
7438                 for(var i = 0, len = className.length; i < len; i++) {
7439                     this.addClass(className[i]);
7440                 }
7441             }else{
7442                 if(className && !this.hasClass(className)){
7443                     this.dom.className = this.dom.className + " " + className;
7444                 }
7445             }
7446             return this;
7447         },
7448
7449         /**
7450          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7451          * @param {String/Array} className The CSS class to add, or an array of classes
7452          * @return {Roo.Element} this
7453          */
7454         radioClass : function(className){
7455             var siblings = this.dom.parentNode.childNodes;
7456             for(var i = 0; i < siblings.length; i++) {
7457                 var s = siblings[i];
7458                 if(s.nodeType == 1){
7459                     Roo.get(s).removeClass(className);
7460                 }
7461             }
7462             this.addClass(className);
7463             return this;
7464         },
7465
7466         /**
7467          * Removes one or more CSS classes from the element.
7468          * @param {String/Array} className The CSS class to remove, or an array of classes
7469          * @return {Roo.Element} this
7470          */
7471         removeClass : function(className){
7472             if(!className || !this.dom.className){
7473                 return this;
7474             }
7475             if(className instanceof Array){
7476                 for(var i = 0, len = className.length; i < len; i++) {
7477                     this.removeClass(className[i]);
7478                 }
7479             }else{
7480                 if(this.hasClass(className)){
7481                     var re = this.classReCache[className];
7482                     if (!re) {
7483                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7484                        this.classReCache[className] = re;
7485                     }
7486                     this.dom.className =
7487                         this.dom.className.replace(re, " ");
7488                 }
7489             }
7490             return this;
7491         },
7492
7493         // private
7494         classReCache: {},
7495
7496         /**
7497          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7498          * @param {String} className The CSS class to toggle
7499          * @return {Roo.Element} this
7500          */
7501         toggleClass : function(className){
7502             if(this.hasClass(className)){
7503                 this.removeClass(className);
7504             }else{
7505                 this.addClass(className);
7506             }
7507             return this;
7508         },
7509
7510         /**
7511          * Checks if the specified CSS class exists on this element's DOM node.
7512          * @param {String} className The CSS class to check for
7513          * @return {Boolean} True if the class exists, else false
7514          */
7515         hasClass : function(className){
7516             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517         },
7518
7519         /**
7520          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7521          * @param {String} oldClassName The CSS class to replace
7522          * @param {String} newClassName The replacement CSS class
7523          * @return {Roo.Element} this
7524          */
7525         replaceClass : function(oldClassName, newClassName){
7526             this.removeClass(oldClassName);
7527             this.addClass(newClassName);
7528             return this;
7529         },
7530
7531         /**
7532          * Returns an object with properties matching the styles requested.
7533          * For example, el.getStyles('color', 'font-size', 'width') might return
7534          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7535          * @param {String} style1 A style name
7536          * @param {String} style2 A style name
7537          * @param {String} etc.
7538          * @return {Object} The style object
7539          */
7540         getStyles : function(){
7541             var a = arguments, len = a.length, r = {};
7542             for(var i = 0; i < len; i++){
7543                 r[a[i]] = this.getStyle(a[i]);
7544             }
7545             return r;
7546         },
7547
7548         /**
7549          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7550          * @param {String} property The style property whose value is returned.
7551          * @return {String} The current value of the style property for this element.
7552          */
7553         getStyle : function(){
7554             return view && view.getComputedStyle ?
7555                 function(prop){
7556                     var el = this.dom, v, cs, camel;
7557                     if(prop == 'float'){
7558                         prop = "cssFloat";
7559                     }
7560                     if(el.style && (v = el.style[prop])){
7561                         return v;
7562                     }
7563                     if(cs = view.getComputedStyle(el, "")){
7564                         if(!(camel = propCache[prop])){
7565                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7566                         }
7567                         return cs[camel];
7568                     }
7569                     return null;
7570                 } :
7571                 function(prop){
7572                     var el = this.dom, v, cs, camel;
7573                     if(prop == 'opacity'){
7574                         if(typeof el.style.filter == 'string'){
7575                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7576                             if(m){
7577                                 var fv = parseFloat(m[1]);
7578                                 if(!isNaN(fv)){
7579                                     return fv ? fv / 100 : 0;
7580                                 }
7581                             }
7582                         }
7583                         return 1;
7584                     }else if(prop == 'float'){
7585                         prop = "styleFloat";
7586                     }
7587                     if(!(camel = propCache[prop])){
7588                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7589                     }
7590                     if(v = el.style[camel]){
7591                         return v;
7592                     }
7593                     if(cs = el.currentStyle){
7594                         return cs[camel];
7595                     }
7596                     return null;
7597                 };
7598         }(),
7599
7600         /**
7601          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7602          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7603          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7604          * @return {Roo.Element} this
7605          */
7606         setStyle : function(prop, value){
7607             if(typeof prop == "string"){
7608                 
7609                 if (prop == 'float') {
7610                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7611                     return this;
7612                 }
7613                 
7614                 var camel;
7615                 if(!(camel = propCache[prop])){
7616                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7617                 }
7618                 
7619                 if(camel == 'opacity') {
7620                     this.setOpacity(value);
7621                 }else{
7622                     this.dom.style[camel] = value;
7623                 }
7624             }else{
7625                 for(var style in prop){
7626                     if(typeof prop[style] != "function"){
7627                        this.setStyle(style, prop[style]);
7628                     }
7629                 }
7630             }
7631             return this;
7632         },
7633
7634         /**
7635          * More flexible version of {@link #setStyle} for setting style properties.
7636          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7637          * a function which returns such a specification.
7638          * @return {Roo.Element} this
7639          */
7640         applyStyles : function(style){
7641             Roo.DomHelper.applyStyles(this.dom, style);
7642             return this;
7643         },
7644
7645         /**
7646           * 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).
7647           * @return {Number} The X position of the element
7648           */
7649         getX : function(){
7650             return D.getX(this.dom);
7651         },
7652
7653         /**
7654           * 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).
7655           * @return {Number} The Y position of the element
7656           */
7657         getY : function(){
7658             return D.getY(this.dom);
7659         },
7660
7661         /**
7662           * 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).
7663           * @return {Array} The XY position of the element
7664           */
7665         getXY : function(){
7666             return D.getXY(this.dom);
7667         },
7668
7669         /**
7670          * 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).
7671          * @param {Number} The X position of the element
7672          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7673          * @return {Roo.Element} this
7674          */
7675         setX : function(x, animate){
7676             if(!animate || !A){
7677                 D.setX(this.dom, x);
7678             }else{
7679                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7680             }
7681             return this;
7682         },
7683
7684         /**
7685          * 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).
7686          * @param {Number} The Y position of the element
7687          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7688          * @return {Roo.Element} this
7689          */
7690         setY : function(y, animate){
7691             if(!animate || !A){
7692                 D.setY(this.dom, y);
7693             }else{
7694                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7695             }
7696             return this;
7697         },
7698
7699         /**
7700          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7701          * @param {String} left The left CSS property value
7702          * @return {Roo.Element} this
7703          */
7704         setLeft : function(left){
7705             this.setStyle("left", this.addUnits(left));
7706             return this;
7707         },
7708
7709         /**
7710          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7711          * @param {String} top The top CSS property value
7712          * @return {Roo.Element} this
7713          */
7714         setTop : function(top){
7715             this.setStyle("top", this.addUnits(top));
7716             return this;
7717         },
7718
7719         /**
7720          * Sets the element's CSS right style.
7721          * @param {String} right The right CSS property value
7722          * @return {Roo.Element} this
7723          */
7724         setRight : function(right){
7725             this.setStyle("right", this.addUnits(right));
7726             return this;
7727         },
7728
7729         /**
7730          * Sets the element's CSS bottom style.
7731          * @param {String} bottom The bottom CSS property value
7732          * @return {Roo.Element} this
7733          */
7734         setBottom : function(bottom){
7735             this.setStyle("bottom", this.addUnits(bottom));
7736             return this;
7737         },
7738
7739         /**
7740          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7741          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7742          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7743          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7744          * @return {Roo.Element} this
7745          */
7746         setXY : function(pos, animate){
7747             if(!animate || !A){
7748                 D.setXY(this.dom, pos);
7749             }else{
7750                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7751             }
7752             return this;
7753         },
7754
7755         /**
7756          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7757          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7758          * @param {Number} x X value for new position (coordinates are page-based)
7759          * @param {Number} y Y value for new position (coordinates are page-based)
7760          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7761          * @return {Roo.Element} this
7762          */
7763         setLocation : function(x, y, animate){
7764             this.setXY([x, y], this.preanim(arguments, 2));
7765             return this;
7766         },
7767
7768         /**
7769          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7770          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7771          * @param {Number} x X value for new position (coordinates are page-based)
7772          * @param {Number} y Y value for new position (coordinates are page-based)
7773          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7774          * @return {Roo.Element} this
7775          */
7776         moveTo : function(x, y, animate){
7777             this.setXY([x, y], this.preanim(arguments, 2));
7778             return this;
7779         },
7780
7781         /**
7782          * Returns the region of the given element.
7783          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7784          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7785          */
7786         getRegion : function(){
7787             return D.getRegion(this.dom);
7788         },
7789
7790         /**
7791          * Returns the offset height of the element
7792          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7793          * @return {Number} The element's height
7794          */
7795         getHeight : function(contentHeight){
7796             var h = this.dom.offsetHeight || 0;
7797             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798         },
7799
7800         /**
7801          * Returns the offset width of the element
7802          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7803          * @return {Number} The element's width
7804          */
7805         getWidth : function(contentWidth){
7806             var w = this.dom.offsetWidth || 0;
7807             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808         },
7809
7810         /**
7811          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7812          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7813          * if a height has not been set using CSS.
7814          * @return {Number}
7815          */
7816         getComputedHeight : function(){
7817             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7818             if(!h){
7819                 h = parseInt(this.getStyle('height'), 10) || 0;
7820                 if(!this.isBorderBox()){
7821                     h += this.getFrameWidth('tb');
7822                 }
7823             }
7824             return h;
7825         },
7826
7827         /**
7828          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7829          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7830          * if a width has not been set using CSS.
7831          * @return {Number}
7832          */
7833         getComputedWidth : function(){
7834             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7835             if(!w){
7836                 w = parseInt(this.getStyle('width'), 10) || 0;
7837                 if(!this.isBorderBox()){
7838                     w += this.getFrameWidth('lr');
7839                 }
7840             }
7841             return w;
7842         },
7843
7844         /**
7845          * Returns the size of the element.
7846          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7847          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7848          */
7849         getSize : function(contentSize){
7850             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851         },
7852
7853         /**
7854          * Returns the width and height of the viewport.
7855          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7856          */
7857         getViewSize : function(){
7858             var d = this.dom, doc = document, aw = 0, ah = 0;
7859             if(d == doc || d == doc.body){
7860                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7861             }else{
7862                 return {
7863                     width : d.clientWidth,
7864                     height: d.clientHeight
7865                 };
7866             }
7867         },
7868
7869         /**
7870          * Returns the value of the "value" attribute
7871          * @param {Boolean} asNumber true to parse the value as a number
7872          * @return {String/Number}
7873          */
7874         getValue : function(asNumber){
7875             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876         },
7877
7878         // private
7879         adjustWidth : function(width){
7880             if(typeof width == "number"){
7881                 if(this.autoBoxAdjust && !this.isBorderBox()){
7882                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7883                 }
7884                 if(width < 0){
7885                     width = 0;
7886                 }
7887             }
7888             return width;
7889         },
7890
7891         // private
7892         adjustHeight : function(height){
7893             if(typeof height == "number"){
7894                if(this.autoBoxAdjust && !this.isBorderBox()){
7895                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7896                }
7897                if(height < 0){
7898                    height = 0;
7899                }
7900             }
7901             return height;
7902         },
7903
7904         /**
7905          * Set the width of the element
7906          * @param {Number} width The new width
7907          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7908          * @return {Roo.Element} this
7909          */
7910         setWidth : function(width, animate){
7911             width = this.adjustWidth(width);
7912             if(!animate || !A){
7913                 this.dom.style.width = this.addUnits(width);
7914             }else{
7915                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7916             }
7917             return this;
7918         },
7919
7920         /**
7921          * Set the height of the element
7922          * @param {Number} height The new height
7923          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7924          * @return {Roo.Element} this
7925          */
7926          setHeight : function(height, animate){
7927             height = this.adjustHeight(height);
7928             if(!animate || !A){
7929                 this.dom.style.height = this.addUnits(height);
7930             }else{
7931                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7932             }
7933             return this;
7934         },
7935
7936         /**
7937          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7938          * @param {Number} width The new width
7939          * @param {Number} height The new height
7940          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7941          * @return {Roo.Element} this
7942          */
7943          setSize : function(width, height, animate){
7944             if(typeof width == "object"){ // in case of object from getSize()
7945                 height = width.height; width = width.width;
7946             }
7947             width = this.adjustWidth(width); height = this.adjustHeight(height);
7948             if(!animate || !A){
7949                 this.dom.style.width = this.addUnits(width);
7950                 this.dom.style.height = this.addUnits(height);
7951             }else{
7952                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7953             }
7954             return this;
7955         },
7956
7957         /**
7958          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7959          * @param {Number} x X value for new position (coordinates are page-based)
7960          * @param {Number} y Y value for new position (coordinates are page-based)
7961          * @param {Number} width The new width
7962          * @param {Number} height The new height
7963          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7964          * @return {Roo.Element} this
7965          */
7966         setBounds : function(x, y, width, height, animate){
7967             if(!animate || !A){
7968                 this.setSize(width, height);
7969                 this.setLocation(x, y);
7970             }else{
7971                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7972                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7973                               this.preanim(arguments, 4), 'motion');
7974             }
7975             return this;
7976         },
7977
7978         /**
7979          * 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.
7980          * @param {Roo.lib.Region} region The region to fill
7981          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7982          * @return {Roo.Element} this
7983          */
7984         setRegion : function(region, animate){
7985             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7986             return this;
7987         },
7988
7989         /**
7990          * Appends an event handler
7991          *
7992          * @param {String}   eventName     The type of event to append
7993          * @param {Function} fn        The method the event invokes
7994          * @param {Object} scope       (optional) The scope (this object) of the fn
7995          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7996          */
7997         addListener : function(eventName, fn, scope, options){
7998             if (this.dom) {
7999                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8000             }
8001         },
8002
8003         /**
8004          * Removes an event handler from this element
8005          * @param {String} eventName the type of event to remove
8006          * @param {Function} fn the method the event invokes
8007          * @return {Roo.Element} this
8008          */
8009         removeListener : function(eventName, fn){
8010             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8011             return this;
8012         },
8013
8014         /**
8015          * Removes all previous added listeners from this element
8016          * @return {Roo.Element} this
8017          */
8018         removeAllListeners : function(){
8019             E.purgeElement(this.dom);
8020             return this;
8021         },
8022
8023         relayEvent : function(eventName, observable){
8024             this.on(eventName, function(e){
8025                 observable.fireEvent(eventName, e);
8026             });
8027         },
8028
8029         /**
8030          * Set the opacity of the element
8031          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8032          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8033          * @return {Roo.Element} this
8034          */
8035          setOpacity : function(opacity, animate){
8036             if(!animate || !A){
8037                 var s = this.dom.style;
8038                 if(Roo.isIE){
8039                     s.zoom = 1;
8040                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8041                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8042                 }else{
8043                     s.opacity = opacity;
8044                 }
8045             }else{
8046                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8047             }
8048             return this;
8049         },
8050
8051         /**
8052          * Gets the left X coordinate
8053          * @param {Boolean} local True to get the local css position instead of page coordinate
8054          * @return {Number}
8055          */
8056         getLeft : function(local){
8057             if(!local){
8058                 return this.getX();
8059             }else{
8060                 return parseInt(this.getStyle("left"), 10) || 0;
8061             }
8062         },
8063
8064         /**
8065          * Gets the right X coordinate of the element (element X position + element width)
8066          * @param {Boolean} local True to get the local css position instead of page coordinate
8067          * @return {Number}
8068          */
8069         getRight : function(local){
8070             if(!local){
8071                 return this.getX() + this.getWidth();
8072             }else{
8073                 return (this.getLeft(true) + this.getWidth()) || 0;
8074             }
8075         },
8076
8077         /**
8078          * Gets the top Y coordinate
8079          * @param {Boolean} local True to get the local css position instead of page coordinate
8080          * @return {Number}
8081          */
8082         getTop : function(local) {
8083             if(!local){
8084                 return this.getY();
8085             }else{
8086                 return parseInt(this.getStyle("top"), 10) || 0;
8087             }
8088         },
8089
8090         /**
8091          * Gets the bottom Y coordinate of the element (element Y position + element height)
8092          * @param {Boolean} local True to get the local css position instead of page coordinate
8093          * @return {Number}
8094          */
8095         getBottom : function(local){
8096             if(!local){
8097                 return this.getY() + this.getHeight();
8098             }else{
8099                 return (this.getTop(true) + this.getHeight()) || 0;
8100             }
8101         },
8102
8103         /**
8104         * Initializes positioning on this element. If a desired position is not passed, it will make the
8105         * the element positioned relative IF it is not already positioned.
8106         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8107         * @param {Number} zIndex (optional) The zIndex to apply
8108         * @param {Number} x (optional) Set the page X position
8109         * @param {Number} y (optional) Set the page Y position
8110         */
8111         position : function(pos, zIndex, x, y){
8112             if(!pos){
8113                if(this.getStyle('position') == 'static'){
8114                    this.setStyle('position', 'relative');
8115                }
8116             }else{
8117                 this.setStyle("position", pos);
8118             }
8119             if(zIndex){
8120                 this.setStyle("z-index", zIndex);
8121             }
8122             if(x !== undefined && y !== undefined){
8123                 this.setXY([x, y]);
8124             }else if(x !== undefined){
8125                 this.setX(x);
8126             }else if(y !== undefined){
8127                 this.setY(y);
8128             }
8129         },
8130
8131         /**
8132         * Clear positioning back to the default when the document was loaded
8133         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8134         * @return {Roo.Element} this
8135          */
8136         clearPositioning : function(value){
8137             value = value ||'';
8138             this.setStyle({
8139                 "left": value,
8140                 "right": value,
8141                 "top": value,
8142                 "bottom": value,
8143                 "z-index": "",
8144                 "position" : "static"
8145             });
8146             return this;
8147         },
8148
8149         /**
8150         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8151         * snapshot before performing an update and then restoring the element.
8152         * @return {Object}
8153         */
8154         getPositioning : function(){
8155             var l = this.getStyle("left");
8156             var t = this.getStyle("top");
8157             return {
8158                 "position" : this.getStyle("position"),
8159                 "left" : l,
8160                 "right" : l ? "" : this.getStyle("right"),
8161                 "top" : t,
8162                 "bottom" : t ? "" : this.getStyle("bottom"),
8163                 "z-index" : this.getStyle("z-index")
8164             };
8165         },
8166
8167         /**
8168          * Gets the width of the border(s) for the specified side(s)
8169          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8170          * passing lr would get the border (l)eft width + the border (r)ight width.
8171          * @return {Number} The width of the sides passed added together
8172          */
8173         getBorderWidth : function(side){
8174             return this.addStyles(side, El.borders);
8175         },
8176
8177         /**
8178          * Gets the width of the padding(s) for the specified side(s)
8179          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8180          * passing lr would get the padding (l)eft + the padding (r)ight.
8181          * @return {Number} The padding of the sides passed added together
8182          */
8183         getPadding : function(side){
8184             return this.addStyles(side, El.paddings);
8185         },
8186
8187         /**
8188         * Set positioning with an object returned by getPositioning().
8189         * @param {Object} posCfg
8190         * @return {Roo.Element} this
8191          */
8192         setPositioning : function(pc){
8193             this.applyStyles(pc);
8194             if(pc.right == "auto"){
8195                 this.dom.style.right = "";
8196             }
8197             if(pc.bottom == "auto"){
8198                 this.dom.style.bottom = "";
8199             }
8200             return this;
8201         },
8202
8203         // private
8204         fixDisplay : function(){
8205             if(this.getStyle("display") == "none"){
8206                 this.setStyle("visibility", "hidden");
8207                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8208                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8209                     this.setStyle("display", "block");
8210                 }
8211             }
8212         },
8213
8214         /**
8215          * Quick set left and top adding default units
8216          * @param {String} left The left CSS property value
8217          * @param {String} top The top CSS property value
8218          * @return {Roo.Element} this
8219          */
8220          setLeftTop : function(left, top){
8221             this.dom.style.left = this.addUnits(left);
8222             this.dom.style.top = this.addUnits(top);
8223             return this;
8224         },
8225
8226         /**
8227          * Move this element relative to its current position.
8228          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8229          * @param {Number} distance How far to move the element in pixels
8230          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8231          * @return {Roo.Element} this
8232          */
8233          move : function(direction, distance, animate){
8234             var xy = this.getXY();
8235             direction = direction.toLowerCase();
8236             switch(direction){
8237                 case "l":
8238                 case "left":
8239                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240                     break;
8241                case "r":
8242                case "right":
8243                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8244                     break;
8245                case "t":
8246                case "top":
8247                case "up":
8248                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8249                     break;
8250                case "b":
8251                case "bottom":
8252                case "down":
8253                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8254                     break;
8255             }
8256             return this;
8257         },
8258
8259         /**
8260          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8261          * @return {Roo.Element} this
8262          */
8263         clip : function(){
8264             if(!this.isClipped){
8265                this.isClipped = true;
8266                this.originalClip = {
8267                    "o": this.getStyle("overflow"),
8268                    "x": this.getStyle("overflow-x"),
8269                    "y": this.getStyle("overflow-y")
8270                };
8271                this.setStyle("overflow", "hidden");
8272                this.setStyle("overflow-x", "hidden");
8273                this.setStyle("overflow-y", "hidden");
8274             }
8275             return this;
8276         },
8277
8278         /**
8279          *  Return clipping (overflow) to original clipping before clip() was called
8280          * @return {Roo.Element} this
8281          */
8282         unclip : function(){
8283             if(this.isClipped){
8284                 this.isClipped = false;
8285                 var o = this.originalClip;
8286                 if(o.o){this.setStyle("overflow", o.o);}
8287                 if(o.x){this.setStyle("overflow-x", o.x);}
8288                 if(o.y){this.setStyle("overflow-y", o.y);}
8289             }
8290             return this;
8291         },
8292
8293
8294         /**
8295          * Gets the x,y coordinates specified by the anchor position on the element.
8296          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8297          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8298          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8299          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8300          * @return {Array} [x, y] An array containing the element's x and y coordinates
8301          */
8302         getAnchorXY : function(anchor, local, s){
8303             //Passing a different size is useful for pre-calculating anchors,
8304             //especially for anchored animations that change the el size.
8305
8306             var w, h, vp = false;
8307             if(!s){
8308                 var d = this.dom;
8309                 if(d == document.body || d == document){
8310                     vp = true;
8311                     w = D.getViewWidth(); h = D.getViewHeight();
8312                 }else{
8313                     w = this.getWidth(); h = this.getHeight();
8314                 }
8315             }else{
8316                 w = s.width;  h = s.height;
8317             }
8318             var x = 0, y = 0, r = Math.round;
8319             switch((anchor || "tl").toLowerCase()){
8320                 case "c":
8321                     x = r(w*.5);
8322                     y = r(h*.5);
8323                 break;
8324                 case "t":
8325                     x = r(w*.5);
8326                     y = 0;
8327                 break;
8328                 case "l":
8329                     x = 0;
8330                     y = r(h*.5);
8331                 break;
8332                 case "r":
8333                     x = w;
8334                     y = r(h*.5);
8335                 break;
8336                 case "b":
8337                     x = r(w*.5);
8338                     y = h;
8339                 break;
8340                 case "tl":
8341                     x = 0;
8342                     y = 0;
8343                 break;
8344                 case "bl":
8345                     x = 0;
8346                     y = h;
8347                 break;
8348                 case "br":
8349                     x = w;
8350                     y = h;
8351                 break;
8352                 case "tr":
8353                     x = w;
8354                     y = 0;
8355                 break;
8356             }
8357             if(local === true){
8358                 return [x, y];
8359             }
8360             if(vp){
8361                 var sc = this.getScroll();
8362                 return [x + sc.left, y + sc.top];
8363             }
8364             //Add the element's offset xy
8365             var o = this.getXY();
8366             return [x+o[0], y+o[1]];
8367         },
8368
8369         /**
8370          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8371          * supported position values.
8372          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8373          * @param {String} position The position to align to.
8374          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8375          * @return {Array} [x, y]
8376          */
8377         getAlignToXY : function(el, p, o){
8378             el = Roo.get(el);
8379             var d = this.dom;
8380             if(!el.dom){
8381                 throw "Element.alignTo with an element that doesn't exist";
8382             }
8383             var c = false; //constrain to viewport
8384             var p1 = "", p2 = "";
8385             o = o || [0,0];
8386
8387             if(!p){
8388                 p = "tl-bl";
8389             }else if(p == "?"){
8390                 p = "tl-bl?";
8391             }else if(p.indexOf("-") == -1){
8392                 p = "tl-" + p;
8393             }
8394             p = p.toLowerCase();
8395             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8396             if(!m){
8397                throw "Element.alignTo with an invalid alignment " + p;
8398             }
8399             p1 = m[1]; p2 = m[2]; c = !!m[3];
8400
8401             //Subtract the aligned el's internal xy from the target's offset xy
8402             //plus custom offset to get the aligned el's new offset xy
8403             var a1 = this.getAnchorXY(p1, true);
8404             var a2 = el.getAnchorXY(p2, false);
8405             var x = a2[0] - a1[0] + o[0];
8406             var y = a2[1] - a1[1] + o[1];
8407             if(c){
8408                 //constrain the aligned el to viewport if necessary
8409                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8410                 // 5px of margin for ie
8411                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8412
8413                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8414                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8415                 //otherwise swap the aligned el to the opposite border of the target.
8416                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8417                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8418                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8419                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8420
8421                var doc = document;
8422                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8423                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8424
8425                if((x+w) > dw + scrollX){
8426                     x = swapX ? r.left-w : dw+scrollX-w;
8427                 }
8428                if(x < scrollX){
8429                    x = swapX ? r.right : scrollX;
8430                }
8431                if((y+h) > dh + scrollY){
8432                     y = swapY ? r.top-h : dh+scrollY-h;
8433                 }
8434                if (y < scrollY){
8435                    y = swapY ? r.bottom : scrollY;
8436                }
8437             }
8438             return [x,y];
8439         },
8440
8441         // private
8442         getConstrainToXY : function(){
8443             var os = {top:0, left:0, bottom:0, right: 0};
8444
8445             return function(el, local, offsets, proposedXY){
8446                 el = Roo.get(el);
8447                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8448
8449                 var vw, vh, vx = 0, vy = 0;
8450                 if(el.dom == document.body || el.dom == document){
8451                     vw = Roo.lib.Dom.getViewWidth();
8452                     vh = Roo.lib.Dom.getViewHeight();
8453                 }else{
8454                     vw = el.dom.clientWidth;
8455                     vh = el.dom.clientHeight;
8456                     if(!local){
8457                         var vxy = el.getXY();
8458                         vx = vxy[0];
8459                         vy = vxy[1];
8460                     }
8461                 }
8462
8463                 var s = el.getScroll();
8464
8465                 vx += offsets.left + s.left;
8466                 vy += offsets.top + s.top;
8467
8468                 vw -= offsets.right;
8469                 vh -= offsets.bottom;
8470
8471                 var vr = vx+vw;
8472                 var vb = vy+vh;
8473
8474                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8475                 var x = xy[0], y = xy[1];
8476                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8477
8478                 // only move it if it needs it
8479                 var moved = false;
8480
8481                 // first validate right/bottom
8482                 if((x + w) > vr){
8483                     x = vr - w;
8484                     moved = true;
8485                 }
8486                 if((y + h) > vb){
8487                     y = vb - h;
8488                     moved = true;
8489                 }
8490                 // then make sure top/left isn't negative
8491                 if(x < vx){
8492                     x = vx;
8493                     moved = true;
8494                 }
8495                 if(y < vy){
8496                     y = vy;
8497                     moved = true;
8498                 }
8499                 return moved ? [x, y] : false;
8500             };
8501         }(),
8502
8503         // private
8504         adjustForConstraints : function(xy, parent, offsets){
8505             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8506         },
8507
8508         /**
8509          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8510          * document it aligns it to the viewport.
8511          * The position parameter is optional, and can be specified in any one of the following formats:
8512          * <ul>
8513          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8514          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8515          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8516          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8517          *   <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
8518          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8519          * </ul>
8520          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8521          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8522          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8523          * that specified in order to enforce the viewport constraints.
8524          * Following are all of the supported anchor positions:
8525     <pre>
8526     Value  Description
8527     -----  -----------------------------
8528     tl     The top left corner (default)
8529     t      The center of the top edge
8530     tr     The top right corner
8531     l      The center of the left edge
8532     c      In the center of the element
8533     r      The center of the right edge
8534     bl     The bottom left corner
8535     b      The center of the bottom edge
8536     br     The bottom right corner
8537     </pre>
8538     Example Usage:
8539     <pre><code>
8540     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8541     el.alignTo("other-el");
8542
8543     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8544     el.alignTo("other-el", "tr?");
8545
8546     // align the bottom right corner of el with the center left edge of other-el
8547     el.alignTo("other-el", "br-l?");
8548
8549     // align the center of el with the bottom left corner of other-el and
8550     // adjust the x position by -6 pixels (and the y position by 0)
8551     el.alignTo("other-el", "c-bl", [-6, 0]);
8552     </code></pre>
8553          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8554          * @param {String} position The position to align to.
8555          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8556          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8557          * @return {Roo.Element} this
8558          */
8559         alignTo : function(element, position, offsets, animate){
8560             var xy = this.getAlignToXY(element, position, offsets);
8561             this.setXY(xy, this.preanim(arguments, 3));
8562             return this;
8563         },
8564
8565         /**
8566          * Anchors an element to another element and realigns it when the window is resized.
8567          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8568          * @param {String} position The position to align to.
8569          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8570          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8571          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8572          * is a number, it is used as the buffer delay (defaults to 50ms).
8573          * @param {Function} callback The function to call after the animation finishes
8574          * @return {Roo.Element} this
8575          */
8576         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8577             var action = function(){
8578                 this.alignTo(el, alignment, offsets, animate);
8579                 Roo.callback(callback, this);
8580             };
8581             Roo.EventManager.onWindowResize(action, this);
8582             var tm = typeof monitorScroll;
8583             if(tm != 'undefined'){
8584                 Roo.EventManager.on(window, 'scroll', action, this,
8585                     {buffer: tm == 'number' ? monitorScroll : 50});
8586             }
8587             action.call(this); // align immediately
8588             return this;
8589         },
8590         /**
8591          * Clears any opacity settings from this element. Required in some cases for IE.
8592          * @return {Roo.Element} this
8593          */
8594         clearOpacity : function(){
8595             if (window.ActiveXObject) {
8596                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8597                     this.dom.style.filter = "";
8598                 }
8599             } else {
8600                 this.dom.style.opacity = "";
8601                 this.dom.style["-moz-opacity"] = "";
8602                 this.dom.style["-khtml-opacity"] = "";
8603             }
8604             return this;
8605         },
8606
8607         /**
8608          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8609          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8610          * @return {Roo.Element} this
8611          */
8612         hide : function(animate){
8613             this.setVisible(false, this.preanim(arguments, 0));
8614             return this;
8615         },
8616
8617         /**
8618         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8619         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8620          * @return {Roo.Element} this
8621          */
8622         show : function(animate){
8623             this.setVisible(true, this.preanim(arguments, 0));
8624             return this;
8625         },
8626
8627         /**
8628          * @private Test if size has a unit, otherwise appends the default
8629          */
8630         addUnits : function(size){
8631             return Roo.Element.addUnits(size, this.defaultUnit);
8632         },
8633
8634         /**
8635          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8636          * @return {Roo.Element} this
8637          */
8638         beginMeasure : function(){
8639             var el = this.dom;
8640             if(el.offsetWidth || el.offsetHeight){
8641                 return this; // offsets work already
8642             }
8643             var changed = [];
8644             var p = this.dom, b = document.body; // start with this element
8645             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8646                 var pe = Roo.get(p);
8647                 if(pe.getStyle('display') == 'none'){
8648                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8649                     p.style.visibility = "hidden";
8650                     p.style.display = "block";
8651                 }
8652                 p = p.parentNode;
8653             }
8654             this._measureChanged = changed;
8655             return this;
8656
8657         },
8658
8659         /**
8660          * Restores displays to before beginMeasure was called
8661          * @return {Roo.Element} this
8662          */
8663         endMeasure : function(){
8664             var changed = this._measureChanged;
8665             if(changed){
8666                 for(var i = 0, len = changed.length; i < len; i++) {
8667                     var r = changed[i];
8668                     r.el.style.visibility = r.visibility;
8669                     r.el.style.display = "none";
8670                 }
8671                 this._measureChanged = null;
8672             }
8673             return this;
8674         },
8675
8676         /**
8677         * Update the innerHTML of this element, optionally searching for and processing scripts
8678         * @param {String} html The new HTML
8679         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8680         * @param {Function} callback For async script loading you can be noticed when the update completes
8681         * @return {Roo.Element} this
8682          */
8683         update : function(html, loadScripts, callback){
8684             if(typeof html == "undefined"){
8685                 html = "";
8686             }
8687             if(loadScripts !== true){
8688                 this.dom.innerHTML = html;
8689                 if(typeof callback == "function"){
8690                     callback();
8691                 }
8692                 return this;
8693             }
8694             var id = Roo.id();
8695             var dom = this.dom;
8696
8697             html += '<span id="' + id + '"></span>';
8698
8699             E.onAvailable(id, function(){
8700                 var hd = document.getElementsByTagName("head")[0];
8701                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8702                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8703                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8704
8705                 var match;
8706                 while(match = re.exec(html)){
8707                     var attrs = match[1];
8708                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8709                     if(srcMatch && srcMatch[2]){
8710                        var s = document.createElement("script");
8711                        s.src = srcMatch[2];
8712                        var typeMatch = attrs.match(typeRe);
8713                        if(typeMatch && typeMatch[2]){
8714                            s.type = typeMatch[2];
8715                        }
8716                        hd.appendChild(s);
8717                     }else if(match[2] && match[2].length > 0){
8718                         if(window.execScript) {
8719                            window.execScript(match[2]);
8720                         } else {
8721                             /**
8722                              * eval:var:id
8723                              * eval:var:dom
8724                              * eval:var:html
8725                              * 
8726                              */
8727                            window.eval(match[2]);
8728                         }
8729                     }
8730                 }
8731                 var el = document.getElementById(id);
8732                 if(el){el.parentNode.removeChild(el);}
8733                 if(typeof callback == "function"){
8734                     callback();
8735                 }
8736             });
8737             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8738             return this;
8739         },
8740
8741         /**
8742          * Direct access to the UpdateManager update() method (takes the same parameters).
8743          * @param {String/Function} url The url for this request or a function to call to get the url
8744          * @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}
8745          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8746          * @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.
8747          * @return {Roo.Element} this
8748          */
8749         load : function(){
8750             var um = this.getUpdateManager();
8751             um.update.apply(um, arguments);
8752             return this;
8753         },
8754
8755         /**
8756         * Gets this element's UpdateManager
8757         * @return {Roo.UpdateManager} The UpdateManager
8758         */
8759         getUpdateManager : function(){
8760             if(!this.updateManager){
8761                 this.updateManager = new Roo.UpdateManager(this);
8762             }
8763             return this.updateManager;
8764         },
8765
8766         /**
8767          * Disables text selection for this element (normalized across browsers)
8768          * @return {Roo.Element} this
8769          */
8770         unselectable : function(){
8771             this.dom.unselectable = "on";
8772             this.swallowEvent("selectstart", true);
8773             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8774             this.addClass("x-unselectable");
8775             return this;
8776         },
8777
8778         /**
8779         * Calculates the x, y to center this element on the screen
8780         * @return {Array} The x, y values [x, y]
8781         */
8782         getCenterXY : function(){
8783             return this.getAlignToXY(document, 'c-c');
8784         },
8785
8786         /**
8787         * Centers the Element in either the viewport, or another Element.
8788         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8789         */
8790         center : function(centerIn){
8791             this.alignTo(centerIn || document, 'c-c');
8792             return this;
8793         },
8794
8795         /**
8796          * Tests various css rules/browsers to determine if this element uses a border box
8797          * @return {Boolean}
8798          */
8799         isBorderBox : function(){
8800             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801         },
8802
8803         /**
8804          * Return a box {x, y, width, height} that can be used to set another elements
8805          * size/location to match this element.
8806          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8807          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8808          * @return {Object} box An object in the format {x, y, width, height}
8809          */
8810         getBox : function(contentBox, local){
8811             var xy;
8812             if(!local){
8813                 xy = this.getXY();
8814             }else{
8815                 var left = parseInt(this.getStyle("left"), 10) || 0;
8816                 var top = parseInt(this.getStyle("top"), 10) || 0;
8817                 xy = [left, top];
8818             }
8819             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8820             if(!contentBox){
8821                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8822             }else{
8823                 var l = this.getBorderWidth("l")+this.getPadding("l");
8824                 var r = this.getBorderWidth("r")+this.getPadding("r");
8825                 var t = this.getBorderWidth("t")+this.getPadding("t");
8826                 var b = this.getBorderWidth("b")+this.getPadding("b");
8827                 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)};
8828             }
8829             bx.right = bx.x + bx.width;
8830             bx.bottom = bx.y + bx.height;
8831             return bx;
8832         },
8833
8834         /**
8835          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8836          for more information about the sides.
8837          * @param {String} sides
8838          * @return {Number}
8839          */
8840         getFrameWidth : function(sides, onlyContentBox){
8841             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842         },
8843
8844         /**
8845          * 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.
8846          * @param {Object} box The box to fill {x, y, width, height}
8847          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8848          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8849          * @return {Roo.Element} this
8850          */
8851         setBox : function(box, adjust, animate){
8852             var w = box.width, h = box.height;
8853             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8854                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8855                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8856             }
8857             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8858             return this;
8859         },
8860
8861         /**
8862          * Forces the browser to repaint this element
8863          * @return {Roo.Element} this
8864          */
8865          repaint : function(){
8866             var dom = this.dom;
8867             this.addClass("x-repaint");
8868             setTimeout(function(){
8869                 Roo.get(dom).removeClass("x-repaint");
8870             }, 1);
8871             return this;
8872         },
8873
8874         /**
8875          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8876          * then it returns the calculated width of the sides (see getPadding)
8877          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8878          * @return {Object/Number}
8879          */
8880         getMargins : function(side){
8881             if(!side){
8882                 return {
8883                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8884                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8885                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8886                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8887                 };
8888             }else{
8889                 return this.addStyles(side, El.margins);
8890              }
8891         },
8892
8893         // private
8894         addStyles : function(sides, styles){
8895             var val = 0, v, w;
8896             for(var i = 0, len = sides.length; i < len; i++){
8897                 v = this.getStyle(styles[sides.charAt(i)]);
8898                 if(v){
8899                      w = parseInt(v, 10);
8900                      if(w){ val += w; }
8901                 }
8902             }
8903             return val;
8904         },
8905
8906         /**
8907          * Creates a proxy element of this element
8908          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8909          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8910          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8911          * @return {Roo.Element} The new proxy element
8912          */
8913         createProxy : function(config, renderTo, matchBox){
8914             if(renderTo){
8915                 renderTo = Roo.getDom(renderTo);
8916             }else{
8917                 renderTo = document.body;
8918             }
8919             config = typeof config == "object" ?
8920                 config : {tag : "div", cls: config};
8921             var proxy = Roo.DomHelper.append(renderTo, config, true);
8922             if(matchBox){
8923                proxy.setBox(this.getBox());
8924             }
8925             return proxy;
8926         },
8927
8928         /**
8929          * Puts a mask over this element to disable user interaction. Requires core.css.
8930          * This method can only be applied to elements which accept child nodes.
8931          * @param {String} msg (optional) A message to display in the mask
8932          * @param {String} msgCls (optional) A css class to apply to the msg element
8933          * @return {Element} The mask  element
8934          */
8935         mask : function(msg, msgCls)
8936         {
8937             if(this.getStyle("position") == "static"){
8938                 this.setStyle("position", "relative");
8939             }
8940             if(!this._mask){
8941                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8942             }
8943             this.addClass("x-masked");
8944             this._mask.setDisplayed(true);
8945             
8946             // we wander
8947             var z = 0;
8948             var dom = this.dom
8949             while (dom && dom.style) {
8950                 if (!isNaN(parseInt(dom.style.zIndex))) {
8951                     z = Math.max(z, parseInt(dom.style.zIndex));
8952                 }
8953                 dom = dom.parentNode;
8954             }
8955             // if we are masking the body - then it hides everything..
8956             if (this.dom == document.body) {
8957                 z = 1000000;
8958                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8959                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8960             }
8961            
8962             if(typeof msg == 'string'){
8963                 if(!this._maskMsg){
8964                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8965                 }
8966                 var mm = this._maskMsg;
8967                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8968                 mm.dom.firstChild.innerHTML = msg;
8969                 mm.setDisplayed(true);
8970                 mm.center(this);
8971                 mm.setStyle('z-index', z + 102);
8972             }
8973             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8974                 this._mask.setHeight(this.getHeight());
8975             }
8976             this._mask.setStyle('z-index', z + 100);
8977             
8978             return this._mask;
8979         },
8980
8981         /**
8982          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8983          * it is cached for reuse.
8984          */
8985         unmask : function(removeEl){
8986             if(this._mask){
8987                 if(removeEl === true){
8988                     this._mask.remove();
8989                     delete this._mask;
8990                     if(this._maskMsg){
8991                         this._maskMsg.remove();
8992                         delete this._maskMsg;
8993                     }
8994                 }else{
8995                     this._mask.setDisplayed(false);
8996                     if(this._maskMsg){
8997                         this._maskMsg.setDisplayed(false);
8998                     }
8999                 }
9000             }
9001             this.removeClass("x-masked");
9002         },
9003
9004         /**
9005          * Returns true if this element is masked
9006          * @return {Boolean}
9007          */
9008         isMasked : function(){
9009             return this._mask && this._mask.isVisible();
9010         },
9011
9012         /**
9013          * Creates an iframe shim for this element to keep selects and other windowed objects from
9014          * showing through.
9015          * @return {Roo.Element} The new shim element
9016          */
9017         createShim : function(){
9018             var el = document.createElement('iframe');
9019             el.frameBorder = 'no';
9020             el.className = 'roo-shim';
9021             if(Roo.isIE && Roo.isSecure){
9022                 el.src = Roo.SSL_SECURE_URL;
9023             }
9024             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9025             shim.autoBoxAdjust = false;
9026             return shim;
9027         },
9028
9029         /**
9030          * Removes this element from the DOM and deletes it from the cache
9031          */
9032         remove : function(){
9033             if(this.dom.parentNode){
9034                 this.dom.parentNode.removeChild(this.dom);
9035             }
9036             delete El.cache[this.dom.id];
9037         },
9038
9039         /**
9040          * Sets up event handlers to add and remove a css class when the mouse is over this element
9041          * @param {String} className
9042          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9043          * mouseout events for children elements
9044          * @return {Roo.Element} this
9045          */
9046         addClassOnOver : function(className, preventFlicker){
9047             this.on("mouseover", function(){
9048                 Roo.fly(this, '_internal').addClass(className);
9049             }, this.dom);
9050             var removeFn = function(e){
9051                 if(preventFlicker !== true || !e.within(this, true)){
9052                     Roo.fly(this, '_internal').removeClass(className);
9053                 }
9054             };
9055             this.on("mouseout", removeFn, this.dom);
9056             return this;
9057         },
9058
9059         /**
9060          * Sets up event handlers to add and remove a css class when this element has the focus
9061          * @param {String} className
9062          * @return {Roo.Element} this
9063          */
9064         addClassOnFocus : function(className){
9065             this.on("focus", function(){
9066                 Roo.fly(this, '_internal').addClass(className);
9067             }, this.dom);
9068             this.on("blur", function(){
9069                 Roo.fly(this, '_internal').removeClass(className);
9070             }, this.dom);
9071             return this;
9072         },
9073         /**
9074          * 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)
9075          * @param {String} className
9076          * @return {Roo.Element} this
9077          */
9078         addClassOnClick : function(className){
9079             var dom = this.dom;
9080             this.on("mousedown", function(){
9081                 Roo.fly(dom, '_internal').addClass(className);
9082                 var d = Roo.get(document);
9083                 var fn = function(){
9084                     Roo.fly(dom, '_internal').removeClass(className);
9085                     d.removeListener("mouseup", fn);
9086                 };
9087                 d.on("mouseup", fn);
9088             });
9089             return this;
9090         },
9091
9092         /**
9093          * Stops the specified event from bubbling and optionally prevents the default action
9094          * @param {String} eventName
9095          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9096          * @return {Roo.Element} this
9097          */
9098         swallowEvent : function(eventName, preventDefault){
9099             var fn = function(e){
9100                 e.stopPropagation();
9101                 if(preventDefault){
9102                     e.preventDefault();
9103                 }
9104             };
9105             if(eventName instanceof Array){
9106                 for(var i = 0, len = eventName.length; i < len; i++){
9107                      this.on(eventName[i], fn);
9108                 }
9109                 return this;
9110             }
9111             this.on(eventName, fn);
9112             return this;
9113         },
9114
9115         /**
9116          * @private
9117          */
9118       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9119
9120         /**
9121          * Sizes this element to its parent element's dimensions performing
9122          * neccessary box adjustments.
9123          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9124          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9125          * @return {Roo.Element} this
9126          */
9127         fitToParent : function(monitorResize, targetParent) {
9128           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9129           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9130           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9131             return;
9132           }
9133           var p = Roo.get(targetParent || this.dom.parentNode);
9134           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9135           if (monitorResize === true) {
9136             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9137             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9138           }
9139           return this;
9140         },
9141
9142         /**
9143          * Gets the next sibling, skipping text nodes
9144          * @return {HTMLElement} The next sibling or null
9145          */
9146         getNextSibling : function(){
9147             var n = this.dom.nextSibling;
9148             while(n && n.nodeType != 1){
9149                 n = n.nextSibling;
9150             }
9151             return n;
9152         },
9153
9154         /**
9155          * Gets the previous sibling, skipping text nodes
9156          * @return {HTMLElement} The previous sibling or null
9157          */
9158         getPrevSibling : function(){
9159             var n = this.dom.previousSibling;
9160             while(n && n.nodeType != 1){
9161                 n = n.previousSibling;
9162             }
9163             return n;
9164         },
9165
9166
9167         /**
9168          * Appends the passed element(s) to this element
9169          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9170          * @return {Roo.Element} this
9171          */
9172         appendChild: function(el){
9173             el = Roo.get(el);
9174             el.appendTo(this);
9175             return this;
9176         },
9177
9178         /**
9179          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9180          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9181          * automatically generated with the specified attributes.
9182          * @param {HTMLElement} insertBefore (optional) a child element of this element
9183          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9184          * @return {Roo.Element} The new child element
9185          */
9186         createChild: function(config, insertBefore, returnDom){
9187             config = config || {tag:'div'};
9188             if(insertBefore){
9189                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9190             }
9191             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9192         },
9193
9194         /**
9195          * Appends this element to the passed element
9196          * @param {String/HTMLElement/Element} el The new parent element
9197          * @return {Roo.Element} this
9198          */
9199         appendTo: function(el){
9200             el = Roo.getDom(el);
9201             el.appendChild(this.dom);
9202             return this;
9203         },
9204
9205         /**
9206          * Inserts this element before the passed element in the DOM
9207          * @param {String/HTMLElement/Element} el The element to insert before
9208          * @return {Roo.Element} this
9209          */
9210         insertBefore: function(el){
9211             el = Roo.getDom(el);
9212             el.parentNode.insertBefore(this.dom, el);
9213             return this;
9214         },
9215
9216         /**
9217          * Inserts this element after the passed element in the DOM
9218          * @param {String/HTMLElement/Element} el The element to insert after
9219          * @return {Roo.Element} this
9220          */
9221         insertAfter: function(el){
9222             el = Roo.getDom(el);
9223             el.parentNode.insertBefore(this.dom, el.nextSibling);
9224             return this;
9225         },
9226
9227         /**
9228          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9229          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9230          * @return {Roo.Element} The new child
9231          */
9232         insertFirst: function(el, returnDom){
9233             el = el || {};
9234             if(typeof el == 'object' && !el.nodeType){ // dh config
9235                 return this.createChild(el, this.dom.firstChild, returnDom);
9236             }else{
9237                 el = Roo.getDom(el);
9238                 this.dom.insertBefore(el, this.dom.firstChild);
9239                 return !returnDom ? Roo.get(el) : el;
9240             }
9241         },
9242
9243         /**
9244          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9245          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9246          * @param {String} where (optional) 'before' or 'after' defaults to before
9247          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9248          * @return {Roo.Element} the inserted Element
9249          */
9250         insertSibling: function(el, where, returnDom){
9251             where = where ? where.toLowerCase() : 'before';
9252             el = el || {};
9253             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9254
9255             if(typeof el == 'object' && !el.nodeType){ // dh config
9256                 if(where == 'after' && !this.dom.nextSibling){
9257                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9258                 }else{
9259                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260                 }
9261
9262             }else{
9263                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9264                             where == 'before' ? this.dom : this.dom.nextSibling);
9265                 if(!returnDom){
9266                     rt = Roo.get(rt);
9267                 }
9268             }
9269             return rt;
9270         },
9271
9272         /**
9273          * Creates and wraps this element with another element
9274          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9275          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9276          * @return {HTMLElement/Element} The newly created wrapper element
9277          */
9278         wrap: function(config, returnDom){
9279             if(!config){
9280                 config = {tag: "div"};
9281             }
9282             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9283             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9284             return newEl;
9285         },
9286
9287         /**
9288          * Replaces the passed element with this element
9289          * @param {String/HTMLElement/Element} el The element to replace
9290          * @return {Roo.Element} this
9291          */
9292         replace: function(el){
9293             el = Roo.get(el);
9294             this.insertBefore(el);
9295             el.remove();
9296             return this;
9297         },
9298
9299         /**
9300          * Inserts an html fragment into this element
9301          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9302          * @param {String} html The HTML fragment
9303          * @param {Boolean} returnEl True to return an Roo.Element
9304          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9305          */
9306         insertHtml : function(where, html, returnEl){
9307             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9308             return returnEl ? Roo.get(el) : el;
9309         },
9310
9311         /**
9312          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9313          * @param {Object} o The object with the attributes
9314          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9315          * @return {Roo.Element} this
9316          */
9317         set : function(o, useSet){
9318             var el = this.dom;
9319             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9320             for(var attr in o){
9321                 if(attr == "style" || typeof o[attr] == "function") continue;
9322                 if(attr=="cls"){
9323                     el.className = o["cls"];
9324                 }else{
9325                     if(useSet) el.setAttribute(attr, o[attr]);
9326                     else el[attr] = o[attr];
9327                 }
9328             }
9329             if(o.style){
9330                 Roo.DomHelper.applyStyles(el, o.style);
9331             }
9332             return this;
9333         },
9334
9335         /**
9336          * Convenience method for constructing a KeyMap
9337          * @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:
9338          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9339          * @param {Function} fn The function to call
9340          * @param {Object} scope (optional) The scope of the function
9341          * @return {Roo.KeyMap} The KeyMap created
9342          */
9343         addKeyListener : function(key, fn, scope){
9344             var config;
9345             if(typeof key != "object" || key instanceof Array){
9346                 config = {
9347                     key: key,
9348                     fn: fn,
9349                     scope: scope
9350                 };
9351             }else{
9352                 config = {
9353                     key : key.key,
9354                     shift : key.shift,
9355                     ctrl : key.ctrl,
9356                     alt : key.alt,
9357                     fn: fn,
9358                     scope: scope
9359                 };
9360             }
9361             return new Roo.KeyMap(this, config);
9362         },
9363
9364         /**
9365          * Creates a KeyMap for this element
9366          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9367          * @return {Roo.KeyMap} The KeyMap created
9368          */
9369         addKeyMap : function(config){
9370             return new Roo.KeyMap(this, config);
9371         },
9372
9373         /**
9374          * Returns true if this element is scrollable.
9375          * @return {Boolean}
9376          */
9377          isScrollable : function(){
9378             var dom = this.dom;
9379             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380         },
9381
9382         /**
9383          * 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().
9384          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9385          * @param {Number} value The new scroll value
9386          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9387          * @return {Element} this
9388          */
9389
9390         scrollTo : function(side, value, animate){
9391             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9392             if(!animate || !A){
9393                 this.dom[prop] = value;
9394             }else{
9395                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9396                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9397             }
9398             return this;
9399         },
9400
9401         /**
9402          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9403          * within this element's scrollable range.
9404          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9405          * @param {Number} distance How far to scroll the element in pixels
9406          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9407          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9408          * was scrolled as far as it could go.
9409          */
9410          scroll : function(direction, distance, animate){
9411              if(!this.isScrollable()){
9412                  return;
9413              }
9414              var el = this.dom;
9415              var l = el.scrollLeft, t = el.scrollTop;
9416              var w = el.scrollWidth, h = el.scrollHeight;
9417              var cw = el.clientWidth, ch = el.clientHeight;
9418              direction = direction.toLowerCase();
9419              var scrolled = false;
9420              var a = this.preanim(arguments, 2);
9421              switch(direction){
9422                  case "l":
9423                  case "left":
9424                      if(w - l > cw){
9425                          var v = Math.min(l + distance, w-cw);
9426                          this.scrollTo("left", v, a);
9427                          scrolled = true;
9428                      }
9429                      break;
9430                 case "r":
9431                 case "right":
9432                      if(l > 0){
9433                          var v = Math.max(l - distance, 0);
9434                          this.scrollTo("left", v, a);
9435                          scrolled = true;
9436                      }
9437                      break;
9438                 case "t":
9439                 case "top":
9440                 case "up":
9441                      if(t > 0){
9442                          var v = Math.max(t - distance, 0);
9443                          this.scrollTo("top", v, a);
9444                          scrolled = true;
9445                      }
9446                      break;
9447                 case "b":
9448                 case "bottom":
9449                 case "down":
9450                      if(h - t > ch){
9451                          var v = Math.min(t + distance, h-ch);
9452                          this.scrollTo("top", v, a);
9453                          scrolled = true;
9454                      }
9455                      break;
9456              }
9457              return scrolled;
9458         },
9459
9460         /**
9461          * Translates the passed page coordinates into left/top css values for this element
9462          * @param {Number/Array} x The page x or an array containing [x, y]
9463          * @param {Number} y The page y
9464          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9465          */
9466         translatePoints : function(x, y){
9467             if(typeof x == 'object' || x instanceof Array){
9468                 y = x[1]; x = x[0];
9469             }
9470             var p = this.getStyle('position');
9471             var o = this.getXY();
9472
9473             var l = parseInt(this.getStyle('left'), 10);
9474             var t = parseInt(this.getStyle('top'), 10);
9475
9476             if(isNaN(l)){
9477                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9478             }
9479             if(isNaN(t)){
9480                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9481             }
9482
9483             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484         },
9485
9486         /**
9487          * Returns the current scroll position of the element.
9488          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9489          */
9490         getScroll : function(){
9491             var d = this.dom, doc = document;
9492             if(d == doc || d == doc.body){
9493                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9494                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9495                 return {left: l, top: t};
9496             }else{
9497                 return {left: d.scrollLeft, top: d.scrollTop};
9498             }
9499         },
9500
9501         /**
9502          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9503          * are convert to standard 6 digit hex color.
9504          * @param {String} attr The css attribute
9505          * @param {String} defaultValue The default value to use when a valid color isn't found
9506          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9507          * YUI color anims.
9508          */
9509         getColor : function(attr, defaultValue, prefix){
9510             var v = this.getStyle(attr);
9511             if(!v || v == "transparent" || v == "inherit") {
9512                 return defaultValue;
9513             }
9514             var color = typeof prefix == "undefined" ? "#" : prefix;
9515             if(v.substr(0, 4) == "rgb("){
9516                 var rvs = v.slice(4, v.length -1).split(",");
9517                 for(var i = 0; i < 3; i++){
9518                     var h = parseInt(rvs[i]).toString(16);
9519                     if(h < 16){
9520                         h = "0" + h;
9521                     }
9522                     color += h;
9523                 }
9524             } else {
9525                 if(v.substr(0, 1) == "#"){
9526                     if(v.length == 4) {
9527                         for(var i = 1; i < 4; i++){
9528                             var c = v.charAt(i);
9529                             color +=  c + c;
9530                         }
9531                     }else if(v.length == 7){
9532                         color += v.substr(1);
9533                     }
9534                 }
9535             }
9536             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537         },
9538
9539         /**
9540          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9541          * gradient background, rounded corners and a 4-way shadow.
9542          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9543          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9544          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9545          * @return {Roo.Element} this
9546          */
9547         boxWrap : function(cls){
9548             cls = cls || 'x-box';
9549             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9550             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9551             return el;
9552         },
9553
9554         /**
9555          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9556          * @param {String} namespace The namespace in which to look for the attribute
9557          * @param {String} name The attribute name
9558          * @return {String} The attribute value
9559          */
9560         getAttributeNS : Roo.isIE ? function(ns, name){
9561             var d = this.dom;
9562             var type = typeof d[ns+":"+name];
9563             if(type != 'undefined' && type != 'unknown'){
9564                 return d[ns+":"+name];
9565             }
9566             return d[name];
9567         } : function(ns, name){
9568             var d = this.dom;
9569             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9570         },
9571         
9572         
9573         /**
9574          * Sets or Returns the value the dom attribute value
9575          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9576          * @param {String} value (optional) The value to set the attribute to
9577          * @return {String} The attribute value
9578          */
9579         attr : function(name){
9580             if (arguments.length > 1) {
9581                 this.dom.setAttribute(name, arguments[1]);
9582                 return arguments[1];
9583             }
9584             if (typeof(name) == 'object') {
9585                 for(var i in name) {
9586                     this.attr(i, name[i]);
9587                 }
9588                 return name;
9589             }
9590             
9591             
9592             if (!this.dom.hasAttribute(name)) {
9593                 return undefined;
9594             }
9595             return this.dom.getAttribute(name);
9596         }
9597         
9598         
9599         
9600     };
9601
9602     var ep = El.prototype;
9603
9604     /**
9605      * Appends an event handler (Shorthand for addListener)
9606      * @param {String}   eventName     The type of event to append
9607      * @param {Function} fn        The method the event invokes
9608      * @param {Object} scope       (optional) The scope (this object) of the fn
9609      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9610      * @method
9611      */
9612     ep.on = ep.addListener;
9613         // backwards compat
9614     ep.mon = ep.addListener;
9615
9616     /**
9617      * Removes an event handler from this element (shorthand for removeListener)
9618      * @param {String} eventName the type of event to remove
9619      * @param {Function} fn the method the event invokes
9620      * @return {Roo.Element} this
9621      * @method
9622      */
9623     ep.un = ep.removeListener;
9624
9625     /**
9626      * true to automatically adjust width and height settings for box-model issues (default to true)
9627      */
9628     ep.autoBoxAdjust = true;
9629
9630     // private
9631     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9632
9633     // private
9634     El.addUnits = function(v, defaultUnit){
9635         if(v === "" || v == "auto"){
9636             return v;
9637         }
9638         if(v === undefined){
9639             return '';
9640         }
9641         if(typeof v == "number" || !El.unitPattern.test(v)){
9642             return v + (defaultUnit || 'px');
9643         }
9644         return v;
9645     };
9646
9647     // special markup used throughout Roo when box wrapping elements
9648     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>';
9649     /**
9650      * Visibility mode constant - Use visibility to hide element
9651      * @static
9652      * @type Number
9653      */
9654     El.VISIBILITY = 1;
9655     /**
9656      * Visibility mode constant - Use display to hide element
9657      * @static
9658      * @type Number
9659      */
9660     El.DISPLAY = 2;
9661
9662     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9663     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9664     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9665
9666
9667
9668     /**
9669      * @private
9670      */
9671     El.cache = {};
9672
9673     var docEl;
9674
9675     /**
9676      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9677      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9678      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9679      * @return {Element} The Element object
9680      * @static
9681      */
9682     El.get = function(el){
9683         var ex, elm, id;
9684         if(!el){ return null; }
9685         if(typeof el == "string"){ // element id
9686             if(!(elm = document.getElementById(el))){
9687                 return null;
9688             }
9689             if(ex = El.cache[el]){
9690                 ex.dom = elm;
9691             }else{
9692                 ex = El.cache[el] = new El(elm);
9693             }
9694             return ex;
9695         }else if(el.tagName){ // dom element
9696             if(!(id = el.id)){
9697                 id = Roo.id(el);
9698             }
9699             if(ex = El.cache[id]){
9700                 ex.dom = el;
9701             }else{
9702                 ex = El.cache[id] = new El(el);
9703             }
9704             return ex;
9705         }else if(el instanceof El){
9706             if(el != docEl){
9707                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9708                                                               // catch case where it hasn't been appended
9709                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9710             }
9711             return el;
9712         }else if(el.isComposite){
9713             return el;
9714         }else if(el instanceof Array){
9715             return El.select(el);
9716         }else if(el == document){
9717             // create a bogus element object representing the document object
9718             if(!docEl){
9719                 var f = function(){};
9720                 f.prototype = El.prototype;
9721                 docEl = new f();
9722                 docEl.dom = document;
9723             }
9724             return docEl;
9725         }
9726         return null;
9727     };
9728
9729     // private
9730     El.uncache = function(el){
9731         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9732             if(a[i]){
9733                 delete El.cache[a[i].id || a[i]];
9734             }
9735         }
9736     };
9737
9738     // private
9739     // Garbage collection - uncache elements/purge listeners on orphaned elements
9740     // so we don't hold a reference and cause the browser to retain them
9741     El.garbageCollect = function(){
9742         if(!Roo.enableGarbageCollector){
9743             clearInterval(El.collectorThread);
9744             return;
9745         }
9746         for(var eid in El.cache){
9747             var el = El.cache[eid], d = el.dom;
9748             // -------------------------------------------------------
9749             // Determining what is garbage:
9750             // -------------------------------------------------------
9751             // !d
9752             // dom node is null, definitely garbage
9753             // -------------------------------------------------------
9754             // !d.parentNode
9755             // no parentNode == direct orphan, definitely garbage
9756             // -------------------------------------------------------
9757             // !d.offsetParent && !document.getElementById(eid)
9758             // display none elements have no offsetParent so we will
9759             // also try to look it up by it's id. However, check
9760             // offsetParent first so we don't do unneeded lookups.
9761             // This enables collection of elements that are not orphans
9762             // directly, but somewhere up the line they have an orphan
9763             // parent.
9764             // -------------------------------------------------------
9765             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9766                 delete El.cache[eid];
9767                 if(d && Roo.enableListenerCollection){
9768                     E.purgeElement(d);
9769                 }
9770             }
9771         }
9772     }
9773     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9774
9775
9776     // dom is optional
9777     El.Flyweight = function(dom){
9778         this.dom = dom;
9779     };
9780     El.Flyweight.prototype = El.prototype;
9781
9782     El._flyweights = {};
9783     /**
9784      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9785      * the dom node can be overwritten by other code.
9786      * @param {String/HTMLElement} el The dom node or id
9787      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9788      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9789      * @static
9790      * @return {Element} The shared Element object
9791      */
9792     El.fly = function(el, named){
9793         named = named || '_global';
9794         el = Roo.getDom(el);
9795         if(!el){
9796             return null;
9797         }
9798         if(!El._flyweights[named]){
9799             El._flyweights[named] = new El.Flyweight();
9800         }
9801         El._flyweights[named].dom = el;
9802         return El._flyweights[named];
9803     };
9804
9805     /**
9806      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9807      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9808      * Shorthand of {@link Roo.Element#get}
9809      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9810      * @return {Element} The Element object
9811      * @member Roo
9812      * @method get
9813      */
9814     Roo.get = El.get;
9815     /**
9816      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9817      * the dom node can be overwritten by other code.
9818      * Shorthand of {@link Roo.Element#fly}
9819      * @param {String/HTMLElement} el The dom node or id
9820      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9821      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9822      * @static
9823      * @return {Element} The shared Element object
9824      * @member Roo
9825      * @method fly
9826      */
9827     Roo.fly = El.fly;
9828
9829     // speedy lookup for elements never to box adjust
9830     var noBoxAdjust = Roo.isStrict ? {
9831         select:1
9832     } : {
9833         input:1, select:1, textarea:1
9834     };
9835     if(Roo.isIE || Roo.isGecko){
9836         noBoxAdjust['button'] = 1;
9837     }
9838
9839
9840     Roo.EventManager.on(window, 'unload', function(){
9841         delete El.cache;
9842         delete El._flyweights;
9843     });
9844 })();
9845
9846
9847
9848
9849 if(Roo.DomQuery){
9850     Roo.Element.selectorFunction = Roo.DomQuery.select;
9851 }
9852
9853 Roo.Element.select = function(selector, unique, root){
9854     var els;
9855     if(typeof selector == "string"){
9856         els = Roo.Element.selectorFunction(selector, root);
9857     }else if(selector.length !== undefined){
9858         els = selector;
9859     }else{
9860         throw "Invalid selector";
9861     }
9862     if(unique === true){
9863         return new Roo.CompositeElement(els);
9864     }else{
9865         return new Roo.CompositeElementLite(els);
9866     }
9867 };
9868 /**
9869  * Selects elements based on the passed CSS selector to enable working on them as 1.
9870  * @param {String/Array} selector The CSS selector or an array of elements
9871  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9872  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9873  * @return {CompositeElementLite/CompositeElement}
9874  * @member Roo
9875  * @method select
9876  */
9877 Roo.select = Roo.Element.select;
9878
9879
9880
9881
9882
9883
9884
9885
9886
9887
9888
9889
9890
9891
9892 /*
9893  * Based on:
9894  * Ext JS Library 1.1.1
9895  * Copyright(c) 2006-2007, Ext JS, LLC.
9896  *
9897  * Originally Released Under LGPL - original licence link has changed is not relivant.
9898  *
9899  * Fork - LGPL
9900  * <script type="text/javascript">
9901  */
9902
9903
9904
9905 //Notifies Element that fx methods are available
9906 Roo.enableFx = true;
9907
9908 /**
9909  * @class Roo.Fx
9910  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9911  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9912  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9913  * Element effects to work.</p><br/>
9914  *
9915  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9916  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9917  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9918  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9919  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9920  * expected results and should be done with care.</p><br/>
9921  *
9922  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9923  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9924 <pre>
9925 Value  Description
9926 -----  -----------------------------
9927 tl     The top left corner
9928 t      The center of the top edge
9929 tr     The top right corner
9930 l      The center of the left edge
9931 r      The center of the right edge
9932 bl     The bottom left corner
9933 b      The center of the bottom edge
9934 br     The bottom right corner
9935 </pre>
9936  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9937  * below are common options that can be passed to any Fx method.</b>
9938  * @cfg {Function} callback A function called when the effect is finished
9939  * @cfg {Object} scope The scope of the effect function
9940  * @cfg {String} easing A valid Easing value for the effect
9941  * @cfg {String} afterCls A css class to apply after the effect
9942  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9943  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9944  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9945  * effects that end with the element being visually hidden, ignored otherwise)
9946  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9947  * a function which returns such a specification that will be applied to the Element after the effect finishes
9948  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9949  * @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
9950  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9951  */
9952 Roo.Fx = {
9953         /**
9954          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9955          * origin for the slide effect.  This function automatically handles wrapping the element with
9956          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9957          * Usage:
9958          *<pre><code>
9959 // default: slide the element in from the top
9960 el.slideIn();
9961
9962 // custom: slide the element in from the right with a 2-second duration
9963 el.slideIn('r', { duration: 2 });
9964
9965 // common config options shown with default values
9966 el.slideIn('t', {
9967     easing: 'easeOut',
9968     duration: .5
9969 });
9970 </code></pre>
9971          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9972          * @param {Object} options (optional) Object literal with any of the Fx config options
9973          * @return {Roo.Element} The Element
9974          */
9975     slideIn : function(anchor, o){
9976         var el = this.getFxEl();
9977         o = o || {};
9978
9979         el.queueFx(o, function(){
9980
9981             anchor = anchor || "t";
9982
9983             // fix display to visibility
9984             this.fixDisplay();
9985
9986             // restore values after effect
9987             var r = this.getFxRestore();
9988             var b = this.getBox();
9989             // fixed size for slide
9990             this.setSize(b);
9991
9992             // wrap if needed
9993             var wrap = this.fxWrap(r.pos, o, "hidden");
9994
9995             var st = this.dom.style;
9996             st.visibility = "visible";
9997             st.position = "absolute";
9998
9999             // clear out temp styles after slide and unwrap
10000             var after = function(){
10001                 el.fxUnwrap(wrap, r.pos, o);
10002                 st.width = r.width;
10003                 st.height = r.height;
10004                 el.afterFx(o);
10005             };
10006             // time to calc the positions
10007             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10008
10009             switch(anchor.toLowerCase()){
10010                 case "t":
10011                     wrap.setSize(b.width, 0);
10012                     st.left = st.bottom = "0";
10013                     a = {height: bh};
10014                 break;
10015                 case "l":
10016                     wrap.setSize(0, b.height);
10017                     st.right = st.top = "0";
10018                     a = {width: bw};
10019                 break;
10020                 case "r":
10021                     wrap.setSize(0, b.height);
10022                     wrap.setX(b.right);
10023                     st.left = st.top = "0";
10024                     a = {width: bw, points: pt};
10025                 break;
10026                 case "b":
10027                     wrap.setSize(b.width, 0);
10028                     wrap.setY(b.bottom);
10029                     st.left = st.top = "0";
10030                     a = {height: bh, points: pt};
10031                 break;
10032                 case "tl":
10033                     wrap.setSize(0, 0);
10034                     st.right = st.bottom = "0";
10035                     a = {width: bw, height: bh};
10036                 break;
10037                 case "bl":
10038                     wrap.setSize(0, 0);
10039                     wrap.setY(b.y+b.height);
10040                     st.right = st.top = "0";
10041                     a = {width: bw, height: bh, points: pt};
10042                 break;
10043                 case "br":
10044                     wrap.setSize(0, 0);
10045                     wrap.setXY([b.right, b.bottom]);
10046                     st.left = st.top = "0";
10047                     a = {width: bw, height: bh, points: pt};
10048                 break;
10049                 case "tr":
10050                     wrap.setSize(0, 0);
10051                     wrap.setX(b.x+b.width);
10052                     st.left = st.bottom = "0";
10053                     a = {width: bw, height: bh, points: pt};
10054                 break;
10055             }
10056             this.dom.style.visibility = "visible";
10057             wrap.show();
10058
10059             arguments.callee.anim = wrap.fxanim(a,
10060                 o,
10061                 'motion',
10062                 .5,
10063                 'easeOut', after);
10064         });
10065         return this;
10066     },
10067     
10068         /**
10069          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10070          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10071          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10072          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10073          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10074          * Usage:
10075          *<pre><code>
10076 // default: slide the element out to the top
10077 el.slideOut();
10078
10079 // custom: slide the element out to the right with a 2-second duration
10080 el.slideOut('r', { duration: 2 });
10081
10082 // common config options shown with default values
10083 el.slideOut('t', {
10084     easing: 'easeOut',
10085     duration: .5,
10086     remove: false,
10087     useDisplay: false
10088 });
10089 </code></pre>
10090          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10091          * @param {Object} options (optional) Object literal with any of the Fx config options
10092          * @return {Roo.Element} The Element
10093          */
10094     slideOut : function(anchor, o){
10095         var el = this.getFxEl();
10096         o = o || {};
10097
10098         el.queueFx(o, function(){
10099
10100             anchor = anchor || "t";
10101
10102             // restore values after effect
10103             var r = this.getFxRestore();
10104             
10105             var b = this.getBox();
10106             // fixed size for slide
10107             this.setSize(b);
10108
10109             // wrap if needed
10110             var wrap = this.fxWrap(r.pos, o, "visible");
10111
10112             var st = this.dom.style;
10113             st.visibility = "visible";
10114             st.position = "absolute";
10115
10116             wrap.setSize(b);
10117
10118             var after = function(){
10119                 if(o.useDisplay){
10120                     el.setDisplayed(false);
10121                 }else{
10122                     el.hide();
10123                 }
10124
10125                 el.fxUnwrap(wrap, r.pos, o);
10126
10127                 st.width = r.width;
10128                 st.height = r.height;
10129
10130                 el.afterFx(o);
10131             };
10132
10133             var a, zero = {to: 0};
10134             switch(anchor.toLowerCase()){
10135                 case "t":
10136                     st.left = st.bottom = "0";
10137                     a = {height: zero};
10138                 break;
10139                 case "l":
10140                     st.right = st.top = "0";
10141                     a = {width: zero};
10142                 break;
10143                 case "r":
10144                     st.left = st.top = "0";
10145                     a = {width: zero, points: {to:[b.right, b.y]}};
10146                 break;
10147                 case "b":
10148                     st.left = st.top = "0";
10149                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10150                 break;
10151                 case "tl":
10152                     st.right = st.bottom = "0";
10153                     a = {width: zero, height: zero};
10154                 break;
10155                 case "bl":
10156                     st.right = st.top = "0";
10157                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10158                 break;
10159                 case "br":
10160                     st.left = st.top = "0";
10161                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10162                 break;
10163                 case "tr":
10164                     st.left = st.bottom = "0";
10165                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10166                 break;
10167             }
10168
10169             arguments.callee.anim = wrap.fxanim(a,
10170                 o,
10171                 'motion',
10172                 .5,
10173                 "easeOut", after);
10174         });
10175         return this;
10176     },
10177
10178         /**
10179          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10180          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10181          * The element must be removed from the DOM using the 'remove' config option if desired.
10182          * Usage:
10183          *<pre><code>
10184 // default
10185 el.puff();
10186
10187 // common config options shown with default values
10188 el.puff({
10189     easing: 'easeOut',
10190     duration: .5,
10191     remove: false,
10192     useDisplay: false
10193 });
10194 </code></pre>
10195          * @param {Object} options (optional) Object literal with any of the Fx config options
10196          * @return {Roo.Element} The Element
10197          */
10198     puff : function(o){
10199         var el = this.getFxEl();
10200         o = o || {};
10201
10202         el.queueFx(o, function(){
10203             this.clearOpacity();
10204             this.show();
10205
10206             // restore values after effect
10207             var r = this.getFxRestore();
10208             var st = this.dom.style;
10209
10210             var after = function(){
10211                 if(o.useDisplay){
10212                     el.setDisplayed(false);
10213                 }else{
10214                     el.hide();
10215                 }
10216
10217                 el.clearOpacity();
10218
10219                 el.setPositioning(r.pos);
10220                 st.width = r.width;
10221                 st.height = r.height;
10222                 st.fontSize = '';
10223                 el.afterFx(o);
10224             };
10225
10226             var width = this.getWidth();
10227             var height = this.getHeight();
10228
10229             arguments.callee.anim = this.fxanim({
10230                     width : {to: this.adjustWidth(width * 2)},
10231                     height : {to: this.adjustHeight(height * 2)},
10232                     points : {by: [-(width * .5), -(height * .5)]},
10233                     opacity : {to: 0},
10234                     fontSize: {to:200, unit: "%"}
10235                 },
10236                 o,
10237                 'motion',
10238                 .5,
10239                 "easeOut", after);
10240         });
10241         return this;
10242     },
10243
10244         /**
10245          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10246          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10247          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10248          * Usage:
10249          *<pre><code>
10250 // default
10251 el.switchOff();
10252
10253 // all config options shown with default values
10254 el.switchOff({
10255     easing: 'easeIn',
10256     duration: .3,
10257     remove: false,
10258     useDisplay: false
10259 });
10260 </code></pre>
10261          * @param {Object} options (optional) Object literal with any of the Fx config options
10262          * @return {Roo.Element} The Element
10263          */
10264     switchOff : function(o){
10265         var el = this.getFxEl();
10266         o = o || {};
10267
10268         el.queueFx(o, function(){
10269             this.clearOpacity();
10270             this.clip();
10271
10272             // restore values after effect
10273             var r = this.getFxRestore();
10274             var st = this.dom.style;
10275
10276             var after = function(){
10277                 if(o.useDisplay){
10278                     el.setDisplayed(false);
10279                 }else{
10280                     el.hide();
10281                 }
10282
10283                 el.clearOpacity();
10284                 el.setPositioning(r.pos);
10285                 st.width = r.width;
10286                 st.height = r.height;
10287
10288                 el.afterFx(o);
10289             };
10290
10291             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10292                 this.clearOpacity();
10293                 (function(){
10294                     this.fxanim({
10295                         height:{to:1},
10296                         points:{by:[0, this.getHeight() * .5]}
10297                     }, o, 'motion', 0.3, 'easeIn', after);
10298                 }).defer(100, this);
10299             });
10300         });
10301         return this;
10302     },
10303
10304     /**
10305      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10306      * changed using the "attr" config option) and then fading back to the original color. If no original
10307      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10308      * Usage:
10309 <pre><code>
10310 // default: highlight background to yellow
10311 el.highlight();
10312
10313 // custom: highlight foreground text to blue for 2 seconds
10314 el.highlight("0000ff", { attr: 'color', duration: 2 });
10315
10316 // common config options shown with default values
10317 el.highlight("ffff9c", {
10318     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10319     endColor: (current color) or "ffffff",
10320     easing: 'easeIn',
10321     duration: 1
10322 });
10323 </code></pre>
10324      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10325      * @param {Object} options (optional) Object literal with any of the Fx config options
10326      * @return {Roo.Element} The Element
10327      */ 
10328     highlight : function(color, o){
10329         var el = this.getFxEl();
10330         o = o || {};
10331
10332         el.queueFx(o, function(){
10333             color = color || "ffff9c";
10334             attr = o.attr || "backgroundColor";
10335
10336             this.clearOpacity();
10337             this.show();
10338
10339             var origColor = this.getColor(attr);
10340             var restoreColor = this.dom.style[attr];
10341             endColor = (o.endColor || origColor) || "ffffff";
10342
10343             var after = function(){
10344                 el.dom.style[attr] = restoreColor;
10345                 el.afterFx(o);
10346             };
10347
10348             var a = {};
10349             a[attr] = {from: color, to: endColor};
10350             arguments.callee.anim = this.fxanim(a,
10351                 o,
10352                 'color',
10353                 1,
10354                 'easeIn', after);
10355         });
10356         return this;
10357     },
10358
10359    /**
10360     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10361     * Usage:
10362 <pre><code>
10363 // default: a single light blue ripple
10364 el.frame();
10365
10366 // custom: 3 red ripples lasting 3 seconds total
10367 el.frame("ff0000", 3, { duration: 3 });
10368
10369 // common config options shown with default values
10370 el.frame("C3DAF9", 1, {
10371     duration: 1 //duration of entire animation (not each individual ripple)
10372     // Note: Easing is not configurable and will be ignored if included
10373 });
10374 </code></pre>
10375     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10376     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10377     * @param {Object} options (optional) Object literal with any of the Fx config options
10378     * @return {Roo.Element} The Element
10379     */
10380     frame : function(color, count, o){
10381         var el = this.getFxEl();
10382         o = o || {};
10383
10384         el.queueFx(o, function(){
10385             color = color || "#C3DAF9";
10386             if(color.length == 6){
10387                 color = "#" + color;
10388             }
10389             count = count || 1;
10390             duration = o.duration || 1;
10391             this.show();
10392
10393             var b = this.getBox();
10394             var animFn = function(){
10395                 var proxy = this.createProxy({
10396
10397                      style:{
10398                         visbility:"hidden",
10399                         position:"absolute",
10400                         "z-index":"35000", // yee haw
10401                         border:"0px solid " + color
10402                      }
10403                   });
10404                 var scale = Roo.isBorderBox ? 2 : 1;
10405                 proxy.animate({
10406                     top:{from:b.y, to:b.y - 20},
10407                     left:{from:b.x, to:b.x - 20},
10408                     borderWidth:{from:0, to:10},
10409                     opacity:{from:1, to:0},
10410                     height:{from:b.height, to:(b.height + (20*scale))},
10411                     width:{from:b.width, to:(b.width + (20*scale))}
10412                 }, duration, function(){
10413                     proxy.remove();
10414                 });
10415                 if(--count > 0){
10416                      animFn.defer((duration/2)*1000, this);
10417                 }else{
10418                     el.afterFx(o);
10419                 }
10420             };
10421             animFn.call(this);
10422         });
10423         return this;
10424     },
10425
10426    /**
10427     * Creates a pause before any subsequent queued effects begin.  If there are
10428     * no effects queued after the pause it will have no effect.
10429     * Usage:
10430 <pre><code>
10431 el.pause(1);
10432 </code></pre>
10433     * @param {Number} seconds The length of time to pause (in seconds)
10434     * @return {Roo.Element} The Element
10435     */
10436     pause : function(seconds){
10437         var el = this.getFxEl();
10438         var o = {};
10439
10440         el.queueFx(o, function(){
10441             setTimeout(function(){
10442                 el.afterFx(o);
10443             }, seconds * 1000);
10444         });
10445         return this;
10446     },
10447
10448    /**
10449     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10450     * using the "endOpacity" config option.
10451     * Usage:
10452 <pre><code>
10453 // default: fade in from opacity 0 to 100%
10454 el.fadeIn();
10455
10456 // custom: fade in from opacity 0 to 75% over 2 seconds
10457 el.fadeIn({ endOpacity: .75, duration: 2});
10458
10459 // common config options shown with default values
10460 el.fadeIn({
10461     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10462     easing: 'easeOut',
10463     duration: .5
10464 });
10465 </code></pre>
10466     * @param {Object} options (optional) Object literal with any of the Fx config options
10467     * @return {Roo.Element} The Element
10468     */
10469     fadeIn : function(o){
10470         var el = this.getFxEl();
10471         o = o || {};
10472         el.queueFx(o, function(){
10473             this.setOpacity(0);
10474             this.fixDisplay();
10475             this.dom.style.visibility = 'visible';
10476             var to = o.endOpacity || 1;
10477             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10478                 o, null, .5, "easeOut", function(){
10479                 if(to == 1){
10480                     this.clearOpacity();
10481                 }
10482                 el.afterFx(o);
10483             });
10484         });
10485         return this;
10486     },
10487
10488    /**
10489     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10490     * using the "endOpacity" config option.
10491     * Usage:
10492 <pre><code>
10493 // default: fade out from the element's current opacity to 0
10494 el.fadeOut();
10495
10496 // custom: fade out from the element's current opacity to 25% over 2 seconds
10497 el.fadeOut({ endOpacity: .25, duration: 2});
10498
10499 // common config options shown with default values
10500 el.fadeOut({
10501     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10502     easing: 'easeOut',
10503     duration: .5
10504     remove: false,
10505     useDisplay: false
10506 });
10507 </code></pre>
10508     * @param {Object} options (optional) Object literal with any of the Fx config options
10509     * @return {Roo.Element} The Element
10510     */
10511     fadeOut : function(o){
10512         var el = this.getFxEl();
10513         o = o || {};
10514         el.queueFx(o, function(){
10515             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10516                 o, null, .5, "easeOut", function(){
10517                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10518                      this.dom.style.display = "none";
10519                 }else{
10520                      this.dom.style.visibility = "hidden";
10521                 }
10522                 this.clearOpacity();
10523                 el.afterFx(o);
10524             });
10525         });
10526         return this;
10527     },
10528
10529    /**
10530     * Animates the transition of an element's dimensions from a starting height/width
10531     * to an ending height/width.
10532     * Usage:
10533 <pre><code>
10534 // change height and width to 100x100 pixels
10535 el.scale(100, 100);
10536
10537 // common config options shown with default values.  The height and width will default to
10538 // the element's existing values if passed as null.
10539 el.scale(
10540     [element's width],
10541     [element's height], {
10542     easing: 'easeOut',
10543     duration: .35
10544 });
10545 </code></pre>
10546     * @param {Number} width  The new width (pass undefined to keep the original width)
10547     * @param {Number} height  The new height (pass undefined to keep the original height)
10548     * @param {Object} options (optional) Object literal with any of the Fx config options
10549     * @return {Roo.Element} The Element
10550     */
10551     scale : function(w, h, o){
10552         this.shift(Roo.apply({}, o, {
10553             width: w,
10554             height: h
10555         }));
10556         return this;
10557     },
10558
10559    /**
10560     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10561     * Any of these properties not specified in the config object will not be changed.  This effect 
10562     * requires that at least one new dimension, position or opacity setting must be passed in on
10563     * the config object in order for the function to have any effect.
10564     * Usage:
10565 <pre><code>
10566 // slide the element horizontally to x position 200 while changing the height and opacity
10567 el.shift({ x: 200, height: 50, opacity: .8 });
10568
10569 // common config options shown with default values.
10570 el.shift({
10571     width: [element's width],
10572     height: [element's height],
10573     x: [element's x position],
10574     y: [element's y position],
10575     opacity: [element's opacity],
10576     easing: 'easeOut',
10577     duration: .35
10578 });
10579 </code></pre>
10580     * @param {Object} options  Object literal with any of the Fx config options
10581     * @return {Roo.Element} The Element
10582     */
10583     shift : function(o){
10584         var el = this.getFxEl();
10585         o = o || {};
10586         el.queueFx(o, function(){
10587             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10588             if(w !== undefined){
10589                 a.width = {to: this.adjustWidth(w)};
10590             }
10591             if(h !== undefined){
10592                 a.height = {to: this.adjustHeight(h)};
10593             }
10594             if(x !== undefined || y !== undefined){
10595                 a.points = {to: [
10596                     x !== undefined ? x : this.getX(),
10597                     y !== undefined ? y : this.getY()
10598                 ]};
10599             }
10600             if(op !== undefined){
10601                 a.opacity = {to: op};
10602             }
10603             if(o.xy !== undefined){
10604                 a.points = {to: o.xy};
10605             }
10606             arguments.callee.anim = this.fxanim(a,
10607                 o, 'motion', .35, "easeOut", function(){
10608                 el.afterFx(o);
10609             });
10610         });
10611         return this;
10612     },
10613
10614         /**
10615          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10616          * ending point of the effect.
10617          * Usage:
10618          *<pre><code>
10619 // default: slide the element downward while fading out
10620 el.ghost();
10621
10622 // custom: slide the element out to the right with a 2-second duration
10623 el.ghost('r', { duration: 2 });
10624
10625 // common config options shown with default values
10626 el.ghost('b', {
10627     easing: 'easeOut',
10628     duration: .5
10629     remove: false,
10630     useDisplay: false
10631 });
10632 </code></pre>
10633          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10634          * @param {Object} options (optional) Object literal with any of the Fx config options
10635          * @return {Roo.Element} The Element
10636          */
10637     ghost : function(anchor, o){
10638         var el = this.getFxEl();
10639         o = o || {};
10640
10641         el.queueFx(o, function(){
10642             anchor = anchor || "b";
10643
10644             // restore values after effect
10645             var r = this.getFxRestore();
10646             var w = this.getWidth(),
10647                 h = this.getHeight();
10648
10649             var st = this.dom.style;
10650
10651             var after = function(){
10652                 if(o.useDisplay){
10653                     el.setDisplayed(false);
10654                 }else{
10655                     el.hide();
10656                 }
10657
10658                 el.clearOpacity();
10659                 el.setPositioning(r.pos);
10660                 st.width = r.width;
10661                 st.height = r.height;
10662
10663                 el.afterFx(o);
10664             };
10665
10666             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10667             switch(anchor.toLowerCase()){
10668                 case "t":
10669                     pt.by = [0, -h];
10670                 break;
10671                 case "l":
10672                     pt.by = [-w, 0];
10673                 break;
10674                 case "r":
10675                     pt.by = [w, 0];
10676                 break;
10677                 case "b":
10678                     pt.by = [0, h];
10679                 break;
10680                 case "tl":
10681                     pt.by = [-w, -h];
10682                 break;
10683                 case "bl":
10684                     pt.by = [-w, h];
10685                 break;
10686                 case "br":
10687                     pt.by = [w, h];
10688                 break;
10689                 case "tr":
10690                     pt.by = [w, -h];
10691                 break;
10692             }
10693
10694             arguments.callee.anim = this.fxanim(a,
10695                 o,
10696                 'motion',
10697                 .5,
10698                 "easeOut", after);
10699         });
10700         return this;
10701     },
10702
10703         /**
10704          * Ensures that all effects queued after syncFx is called on the element are
10705          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10706          * @return {Roo.Element} The Element
10707          */
10708     syncFx : function(){
10709         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10710             block : false,
10711             concurrent : true,
10712             stopFx : false
10713         });
10714         return this;
10715     },
10716
10717         /**
10718          * Ensures that all effects queued after sequenceFx is called on the element are
10719          * run in sequence.  This is the opposite of {@link #syncFx}.
10720          * @return {Roo.Element} The Element
10721          */
10722     sequenceFx : function(){
10723         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10724             block : false,
10725             concurrent : false,
10726             stopFx : false
10727         });
10728         return this;
10729     },
10730
10731         /* @private */
10732     nextFx : function(){
10733         var ef = this.fxQueue[0];
10734         if(ef){
10735             ef.call(this);
10736         }
10737     },
10738
10739         /**
10740          * Returns true if the element has any effects actively running or queued, else returns false.
10741          * @return {Boolean} True if element has active effects, else false
10742          */
10743     hasActiveFx : function(){
10744         return this.fxQueue && this.fxQueue[0];
10745     },
10746
10747         /**
10748          * Stops any running effects and clears the element's internal effects queue if it contains
10749          * any additional effects that haven't started yet.
10750          * @return {Roo.Element} The Element
10751          */
10752     stopFx : function(){
10753         if(this.hasActiveFx()){
10754             var cur = this.fxQueue[0];
10755             if(cur && cur.anim && cur.anim.isAnimated()){
10756                 this.fxQueue = [cur]; // clear out others
10757                 cur.anim.stop(true);
10758             }
10759         }
10760         return this;
10761     },
10762
10763         /* @private */
10764     beforeFx : function(o){
10765         if(this.hasActiveFx() && !o.concurrent){
10766            if(o.stopFx){
10767                this.stopFx();
10768                return true;
10769            }
10770            return false;
10771         }
10772         return true;
10773     },
10774
10775         /**
10776          * Returns true if the element is currently blocking so that no other effect can be queued
10777          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10778          * used to ensure that an effect initiated by a user action runs to completion prior to the
10779          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10780          * @return {Boolean} True if blocking, else false
10781          */
10782     hasFxBlock : function(){
10783         var q = this.fxQueue;
10784         return q && q[0] && q[0].block;
10785     },
10786
10787         /* @private */
10788     queueFx : function(o, fn){
10789         if(!this.fxQueue){
10790             this.fxQueue = [];
10791         }
10792         if(!this.hasFxBlock()){
10793             Roo.applyIf(o, this.fxDefaults);
10794             if(!o.concurrent){
10795                 var run = this.beforeFx(o);
10796                 fn.block = o.block;
10797                 this.fxQueue.push(fn);
10798                 if(run){
10799                     this.nextFx();
10800                 }
10801             }else{
10802                 fn.call(this);
10803             }
10804         }
10805         return this;
10806     },
10807
10808         /* @private */
10809     fxWrap : function(pos, o, vis){
10810         var wrap;
10811         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10812             var wrapXY;
10813             if(o.fixPosition){
10814                 wrapXY = this.getXY();
10815             }
10816             var div = document.createElement("div");
10817             div.style.visibility = vis;
10818             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10819             wrap.setPositioning(pos);
10820             if(wrap.getStyle("position") == "static"){
10821                 wrap.position("relative");
10822             }
10823             this.clearPositioning('auto');
10824             wrap.clip();
10825             wrap.dom.appendChild(this.dom);
10826             if(wrapXY){
10827                 wrap.setXY(wrapXY);
10828             }
10829         }
10830         return wrap;
10831     },
10832
10833         /* @private */
10834     fxUnwrap : function(wrap, pos, o){
10835         this.clearPositioning();
10836         this.setPositioning(pos);
10837         if(!o.wrap){
10838             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10839             wrap.remove();
10840         }
10841     },
10842
10843         /* @private */
10844     getFxRestore : function(){
10845         var st = this.dom.style;
10846         return {pos: this.getPositioning(), width: st.width, height : st.height};
10847     },
10848
10849         /* @private */
10850     afterFx : function(o){
10851         if(o.afterStyle){
10852             this.applyStyles(o.afterStyle);
10853         }
10854         if(o.afterCls){
10855             this.addClass(o.afterCls);
10856         }
10857         if(o.remove === true){
10858             this.remove();
10859         }
10860         Roo.callback(o.callback, o.scope, [this]);
10861         if(!o.concurrent){
10862             this.fxQueue.shift();
10863             this.nextFx();
10864         }
10865     },
10866
10867         /* @private */
10868     getFxEl : function(){ // support for composite element fx
10869         return Roo.get(this.dom);
10870     },
10871
10872         /* @private */
10873     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10874         animType = animType || 'run';
10875         opt = opt || {};
10876         var anim = Roo.lib.Anim[animType](
10877             this.dom, args,
10878             (opt.duration || defaultDur) || .35,
10879             (opt.easing || defaultEase) || 'easeOut',
10880             function(){
10881                 Roo.callback(cb, this);
10882             },
10883             this
10884         );
10885         opt.anim = anim;
10886         return anim;
10887     }
10888 };
10889
10890 // backwords compat
10891 Roo.Fx.resize = Roo.Fx.scale;
10892
10893 //When included, Roo.Fx is automatically applied to Element so that all basic
10894 //effects are available directly via the Element API
10895 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10896  * Based on:
10897  * Ext JS Library 1.1.1
10898  * Copyright(c) 2006-2007, Ext JS, LLC.
10899  *
10900  * Originally Released Under LGPL - original licence link has changed is not relivant.
10901  *
10902  * Fork - LGPL
10903  * <script type="text/javascript">
10904  */
10905
10906
10907 /**
10908  * @class Roo.CompositeElement
10909  * Standard composite class. Creates a Roo.Element for every element in the collection.
10910  * <br><br>
10911  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10912  * actions will be performed on all the elements in this collection.</b>
10913  * <br><br>
10914  * All methods return <i>this</i> and can be chained.
10915  <pre><code>
10916  var els = Roo.select("#some-el div.some-class", true);
10917  // or select directly from an existing element
10918  var el = Roo.get('some-el');
10919  el.select('div.some-class', true);
10920
10921  els.setWidth(100); // all elements become 100 width
10922  els.hide(true); // all elements fade out and hide
10923  // or
10924  els.setWidth(100).hide(true);
10925  </code></pre>
10926  */
10927 Roo.CompositeElement = function(els){
10928     this.elements = [];
10929     this.addElements(els);
10930 };
10931 Roo.CompositeElement.prototype = {
10932     isComposite: true,
10933     addElements : function(els){
10934         if(!els) return this;
10935         if(typeof els == "string"){
10936             els = Roo.Element.selectorFunction(els);
10937         }
10938         var yels = this.elements;
10939         var index = yels.length-1;
10940         for(var i = 0, len = els.length; i < len; i++) {
10941                 yels[++index] = Roo.get(els[i]);
10942         }
10943         return this;
10944     },
10945
10946     /**
10947     * Clears this composite and adds the elements returned by the passed selector.
10948     * @param {String/Array} els A string CSS selector, an array of elements or an element
10949     * @return {CompositeElement} this
10950     */
10951     fill : function(els){
10952         this.elements = [];
10953         this.add(els);
10954         return this;
10955     },
10956
10957     /**
10958     * Filters this composite to only elements that match the passed selector.
10959     * @param {String} selector A string CSS selector
10960     * @param {Boolean} inverse return inverse filter (not matches)
10961     * @return {CompositeElement} this
10962     */
10963     filter : function(selector, inverse){
10964         var els = [];
10965         inverse = inverse || false;
10966         this.each(function(el){
10967             var match = inverse ? !el.is(selector) : el.is(selector);
10968             if(match){
10969                 els[els.length] = el.dom;
10970             }
10971         });
10972         this.fill(els);
10973         return this;
10974     },
10975
10976     invoke : function(fn, args){
10977         var els = this.elements;
10978         for(var i = 0, len = els.length; i < len; i++) {
10979                 Roo.Element.prototype[fn].apply(els[i], args);
10980         }
10981         return this;
10982     },
10983     /**
10984     * Adds elements to this composite.
10985     * @param {String/Array} els A string CSS selector, an array of elements or an element
10986     * @return {CompositeElement} this
10987     */
10988     add : function(els){
10989         if(typeof els == "string"){
10990             this.addElements(Roo.Element.selectorFunction(els));
10991         }else if(els.length !== undefined){
10992             this.addElements(els);
10993         }else{
10994             this.addElements([els]);
10995         }
10996         return this;
10997     },
10998     /**
10999     * Calls the passed function passing (el, this, index) for each element in this composite.
11000     * @param {Function} fn The function to call
11001     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11002     * @return {CompositeElement} this
11003     */
11004     each : function(fn, scope){
11005         var els = this.elements;
11006         for(var i = 0, len = els.length; i < len; i++){
11007             if(fn.call(scope || els[i], els[i], this, i) === false) {
11008                 break;
11009             }
11010         }
11011         return this;
11012     },
11013
11014     /**
11015      * Returns the Element object at the specified index
11016      * @param {Number} index
11017      * @return {Roo.Element}
11018      */
11019     item : function(index){
11020         return this.elements[index] || null;
11021     },
11022
11023     /**
11024      * Returns the first Element
11025      * @return {Roo.Element}
11026      */
11027     first : function(){
11028         return this.item(0);
11029     },
11030
11031     /**
11032      * Returns the last Element
11033      * @return {Roo.Element}
11034      */
11035     last : function(){
11036         return this.item(this.elements.length-1);
11037     },
11038
11039     /**
11040      * Returns the number of elements in this composite
11041      * @return Number
11042      */
11043     getCount : function(){
11044         return this.elements.length;
11045     },
11046
11047     /**
11048      * Returns true if this composite contains the passed element
11049      * @return Boolean
11050      */
11051     contains : function(el){
11052         return this.indexOf(el) !== -1;
11053     },
11054
11055     /**
11056      * Returns true if this composite contains the passed element
11057      * @return Boolean
11058      */
11059     indexOf : function(el){
11060         return this.elements.indexOf(Roo.get(el));
11061     },
11062
11063
11064     /**
11065     * Removes the specified element(s).
11066     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11067     * or an array of any of those.
11068     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11069     * @return {CompositeElement} this
11070     */
11071     removeElement : function(el, removeDom){
11072         if(el instanceof Array){
11073             for(var i = 0, len = el.length; i < len; i++){
11074                 this.removeElement(el[i]);
11075             }
11076             return this;
11077         }
11078         var index = typeof el == 'number' ? el : this.indexOf(el);
11079         if(index !== -1){
11080             if(removeDom){
11081                 var d = this.elements[index];
11082                 if(d.dom){
11083                     d.remove();
11084                 }else{
11085                     d.parentNode.removeChild(d);
11086                 }
11087             }
11088             this.elements.splice(index, 1);
11089         }
11090         return this;
11091     },
11092
11093     /**
11094     * Replaces the specified element with the passed element.
11095     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11096     * to replace.
11097     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11098     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11099     * @return {CompositeElement} this
11100     */
11101     replaceElement : function(el, replacement, domReplace){
11102         var index = typeof el == 'number' ? el : this.indexOf(el);
11103         if(index !== -1){
11104             if(domReplace){
11105                 this.elements[index].replaceWith(replacement);
11106             }else{
11107                 this.elements.splice(index, 1, Roo.get(replacement))
11108             }
11109         }
11110         return this;
11111     },
11112
11113     /**
11114      * Removes all elements.
11115      */
11116     clear : function(){
11117         this.elements = [];
11118     }
11119 };
11120 (function(){
11121     Roo.CompositeElement.createCall = function(proto, fnName){
11122         if(!proto[fnName]){
11123             proto[fnName] = function(){
11124                 return this.invoke(fnName, arguments);
11125             };
11126         }
11127     };
11128     for(var fnName in Roo.Element.prototype){
11129         if(typeof Roo.Element.prototype[fnName] == "function"){
11130             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11131         }
11132     };
11133 })();
11134 /*
11135  * Based on:
11136  * Ext JS Library 1.1.1
11137  * Copyright(c) 2006-2007, Ext JS, LLC.
11138  *
11139  * Originally Released Under LGPL - original licence link has changed is not relivant.
11140  *
11141  * Fork - LGPL
11142  * <script type="text/javascript">
11143  */
11144
11145 /**
11146  * @class Roo.CompositeElementLite
11147  * @extends Roo.CompositeElement
11148  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11149  <pre><code>
11150  var els = Roo.select("#some-el div.some-class");
11151  // or select directly from an existing element
11152  var el = Roo.get('some-el');
11153  el.select('div.some-class');
11154
11155  els.setWidth(100); // all elements become 100 width
11156  els.hide(true); // all elements fade out and hide
11157  // or
11158  els.setWidth(100).hide(true);
11159  </code></pre><br><br>
11160  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11161  * actions will be performed on all the elements in this collection.</b>
11162  */
11163 Roo.CompositeElementLite = function(els){
11164     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11165     this.el = new Roo.Element.Flyweight();
11166 };
11167 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11168     addElements : function(els){
11169         if(els){
11170             if(els instanceof Array){
11171                 this.elements = this.elements.concat(els);
11172             }else{
11173                 var yels = this.elements;
11174                 var index = yels.length-1;
11175                 for(var i = 0, len = els.length; i < len; i++) {
11176                     yels[++index] = els[i];
11177                 }
11178             }
11179         }
11180         return this;
11181     },
11182     invoke : function(fn, args){
11183         var els = this.elements;
11184         var el = this.el;
11185         for(var i = 0, len = els.length; i < len; i++) {
11186             el.dom = els[i];
11187                 Roo.Element.prototype[fn].apply(el, args);
11188         }
11189         return this;
11190     },
11191     /**
11192      * Returns a flyweight Element of the dom element object at the specified index
11193      * @param {Number} index
11194      * @return {Roo.Element}
11195      */
11196     item : function(index){
11197         if(!this.elements[index]){
11198             return null;
11199         }
11200         this.el.dom = this.elements[index];
11201         return this.el;
11202     },
11203
11204     // fixes scope with flyweight
11205     addListener : function(eventName, handler, scope, opt){
11206         var els = this.elements;
11207         for(var i = 0, len = els.length; i < len; i++) {
11208             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11209         }
11210         return this;
11211     },
11212
11213     /**
11214     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11215     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11216     * a reference to the dom node, use el.dom.</b>
11217     * @param {Function} fn The function to call
11218     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11219     * @return {CompositeElement} this
11220     */
11221     each : function(fn, scope){
11222         var els = this.elements;
11223         var el = this.el;
11224         for(var i = 0, len = els.length; i < len; i++){
11225             el.dom = els[i];
11226                 if(fn.call(scope || el, el, this, i) === false){
11227                 break;
11228             }
11229         }
11230         return this;
11231     },
11232
11233     indexOf : function(el){
11234         return this.elements.indexOf(Roo.getDom(el));
11235     },
11236
11237     replaceElement : function(el, replacement, domReplace){
11238         var index = typeof el == 'number' ? el : this.indexOf(el);
11239         if(index !== -1){
11240             replacement = Roo.getDom(replacement);
11241             if(domReplace){
11242                 var d = this.elements[index];
11243                 d.parentNode.insertBefore(replacement, d);
11244                 d.parentNode.removeChild(d);
11245             }
11246             this.elements.splice(index, 1, replacement);
11247         }
11248         return this;
11249     }
11250 });
11251 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11252
11253 /*
11254  * Based on:
11255  * Ext JS Library 1.1.1
11256  * Copyright(c) 2006-2007, Ext JS, LLC.
11257  *
11258  * Originally Released Under LGPL - original licence link has changed is not relivant.
11259  *
11260  * Fork - LGPL
11261  * <script type="text/javascript">
11262  */
11263
11264  
11265
11266 /**
11267  * @class Roo.data.Connection
11268  * @extends Roo.util.Observable
11269  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11270  * either to a configured URL, or to a URL specified at request time.<br><br>
11271  * <p>
11272  * Requests made by this class are asynchronous, and will return immediately. No data from
11273  * the server will be available to the statement immediately following the {@link #request} call.
11274  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11275  * <p>
11276  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11277  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11278  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11279  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11280  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11281  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11282  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11283  * standard DOM methods.
11284  * @constructor
11285  * @param {Object} config a configuration object.
11286  */
11287 Roo.data.Connection = function(config){
11288     Roo.apply(this, config);
11289     this.addEvents({
11290         /**
11291          * @event beforerequest
11292          * Fires before a network request is made to retrieve a data object.
11293          * @param {Connection} conn This Connection object.
11294          * @param {Object} options The options config object passed to the {@link #request} method.
11295          */
11296         "beforerequest" : true,
11297         /**
11298          * @event requestcomplete
11299          * Fires if the request was successfully completed.
11300          * @param {Connection} conn This Connection object.
11301          * @param {Object} response The XHR object containing the response data.
11302          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11303          * @param {Object} options The options config object passed to the {@link #request} method.
11304          */
11305         "requestcomplete" : true,
11306         /**
11307          * @event requestexception
11308          * Fires if an error HTTP status was returned from the server.
11309          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11310          * @param {Connection} conn This Connection object.
11311          * @param {Object} response The XHR object containing the response data.
11312          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11313          * @param {Object} options The options config object passed to the {@link #request} method.
11314          */
11315         "requestexception" : true
11316     });
11317     Roo.data.Connection.superclass.constructor.call(this);
11318 };
11319
11320 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11321     /**
11322      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11323      */
11324     /**
11325      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11326      * extra parameters to each request made by this object. (defaults to undefined)
11327      */
11328     /**
11329      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11330      *  to each request made by this object. (defaults to undefined)
11331      */
11332     /**
11333      * @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)
11334      */
11335     /**
11336      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11337      */
11338     timeout : 30000,
11339     /**
11340      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11341      * @type Boolean
11342      */
11343     autoAbort:false,
11344
11345     /**
11346      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11347      * @type Boolean
11348      */
11349     disableCaching: true,
11350
11351     /**
11352      * Sends an HTTP request to a remote server.
11353      * @param {Object} options An object which may contain the following properties:<ul>
11354      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11355      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11356      * request, a url encoded string or a function to call to get either.</li>
11357      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11358      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11359      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11360      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11361      * <li>options {Object} The parameter to the request call.</li>
11362      * <li>success {Boolean} True if the request succeeded.</li>
11363      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11364      * </ul></li>
11365      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11366      * The callback is passed the following parameters:<ul>
11367      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11368      * <li>options {Object} The parameter to the request call.</li>
11369      * </ul></li>
11370      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11371      * The callback is passed the following parameters:<ul>
11372      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11373      * <li>options {Object} The parameter to the request call.</li>
11374      * </ul></li>
11375      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11376      * for the callback function. Defaults to the browser window.</li>
11377      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11378      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11379      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11380      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11381      * params for the post data. Any params will be appended to the URL.</li>
11382      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11383      * </ul>
11384      * @return {Number} transactionId
11385      */
11386     request : function(o){
11387         if(this.fireEvent("beforerequest", this, o) !== false){
11388             var p = o.params;
11389
11390             if(typeof p == "function"){
11391                 p = p.call(o.scope||window, o);
11392             }
11393             if(typeof p == "object"){
11394                 p = Roo.urlEncode(o.params);
11395             }
11396             if(this.extraParams){
11397                 var extras = Roo.urlEncode(this.extraParams);
11398                 p = p ? (p + '&' + extras) : extras;
11399             }
11400
11401             var url = o.url || this.url;
11402             if(typeof url == 'function'){
11403                 url = url.call(o.scope||window, o);
11404             }
11405
11406             if(o.form){
11407                 var form = Roo.getDom(o.form);
11408                 url = url || form.action;
11409
11410                 var enctype = form.getAttribute("enctype");
11411                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11412                     return this.doFormUpload(o, p, url);
11413                 }
11414                 var f = Roo.lib.Ajax.serializeForm(form);
11415                 p = p ? (p + '&' + f) : f;
11416             }
11417
11418             var hs = o.headers;
11419             if(this.defaultHeaders){
11420                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11421                 if(!o.headers){
11422                     o.headers = hs;
11423                 }
11424             }
11425
11426             var cb = {
11427                 success: this.handleResponse,
11428                 failure: this.handleFailure,
11429                 scope: this,
11430                 argument: {options: o},
11431                 timeout : o.timeout || this.timeout
11432             };
11433
11434             var method = o.method||this.method||(p ? "POST" : "GET");
11435
11436             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11437                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11438             }
11439
11440             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11441                 if(o.autoAbort){
11442                     this.abort();
11443                 }
11444             }else if(this.autoAbort !== false){
11445                 this.abort();
11446             }
11447
11448             if((method == 'GET' && p) || o.xmlData){
11449                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11450                 p = '';
11451             }
11452             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11453             return this.transId;
11454         }else{
11455             Roo.callback(o.callback, o.scope, [o, null, null]);
11456             return null;
11457         }
11458     },
11459
11460     /**
11461      * Determine whether this object has a request outstanding.
11462      * @param {Number} transactionId (Optional) defaults to the last transaction
11463      * @return {Boolean} True if there is an outstanding request.
11464      */
11465     isLoading : function(transId){
11466         if(transId){
11467             return Roo.lib.Ajax.isCallInProgress(transId);
11468         }else{
11469             return this.transId ? true : false;
11470         }
11471     },
11472
11473     /**
11474      * Aborts any outstanding request.
11475      * @param {Number} transactionId (Optional) defaults to the last transaction
11476      */
11477     abort : function(transId){
11478         if(transId || this.isLoading()){
11479             Roo.lib.Ajax.abort(transId || this.transId);
11480         }
11481     },
11482
11483     // private
11484     handleResponse : function(response){
11485         this.transId = false;
11486         var options = response.argument.options;
11487         response.argument = options ? options.argument : null;
11488         this.fireEvent("requestcomplete", this, response, options);
11489         Roo.callback(options.success, options.scope, [response, options]);
11490         Roo.callback(options.callback, options.scope, [options, true, response]);
11491     },
11492
11493     // private
11494     handleFailure : function(response, e){
11495         this.transId = false;
11496         var options = response.argument.options;
11497         response.argument = options ? options.argument : null;
11498         this.fireEvent("requestexception", this, response, options, e);
11499         Roo.callback(options.failure, options.scope, [response, options]);
11500         Roo.callback(options.callback, options.scope, [options, false, response]);
11501     },
11502
11503     // private
11504     doFormUpload : function(o, ps, url){
11505         var id = Roo.id();
11506         var frame = document.createElement('iframe');
11507         frame.id = id;
11508         frame.name = id;
11509         frame.className = 'x-hidden';
11510         if(Roo.isIE){
11511             frame.src = Roo.SSL_SECURE_URL;
11512         }
11513         document.body.appendChild(frame);
11514
11515         if(Roo.isIE){
11516            document.frames[id].name = id;
11517         }
11518
11519         var form = Roo.getDom(o.form);
11520         form.target = id;
11521         form.method = 'POST';
11522         form.enctype = form.encoding = 'multipart/form-data';
11523         if(url){
11524             form.action = url;
11525         }
11526
11527         var hiddens, hd;
11528         if(ps){ // add dynamic params
11529             hiddens = [];
11530             ps = Roo.urlDecode(ps, false);
11531             for(var k in ps){
11532                 if(ps.hasOwnProperty(k)){
11533                     hd = document.createElement('input');
11534                     hd.type = 'hidden';
11535                     hd.name = k;
11536                     hd.value = ps[k];
11537                     form.appendChild(hd);
11538                     hiddens.push(hd);
11539                 }
11540             }
11541         }
11542
11543         function cb(){
11544             var r = {  // bogus response object
11545                 responseText : '',
11546                 responseXML : null
11547             };
11548
11549             r.argument = o ? o.argument : null;
11550
11551             try { //
11552                 var doc;
11553                 if(Roo.isIE){
11554                     doc = frame.contentWindow.document;
11555                 }else {
11556                     doc = (frame.contentDocument || window.frames[id].document);
11557                 }
11558                 if(doc && doc.body){
11559                     r.responseText = doc.body.innerHTML;
11560                 }
11561                 if(doc && doc.XMLDocument){
11562                     r.responseXML = doc.XMLDocument;
11563                 }else {
11564                     r.responseXML = doc;
11565                 }
11566             }
11567             catch(e) {
11568                 // ignore
11569             }
11570
11571             Roo.EventManager.removeListener(frame, 'load', cb, this);
11572
11573             this.fireEvent("requestcomplete", this, r, o);
11574             Roo.callback(o.success, o.scope, [r, o]);
11575             Roo.callback(o.callback, o.scope, [o, true, r]);
11576
11577             setTimeout(function(){document.body.removeChild(frame);}, 100);
11578         }
11579
11580         Roo.EventManager.on(frame, 'load', cb, this);
11581         form.submit();
11582
11583         if(hiddens){ // remove dynamic params
11584             for(var i = 0, len = hiddens.length; i < len; i++){
11585                 form.removeChild(hiddens[i]);
11586             }
11587         }
11588     }
11589 });
11590 /*
11591  * Based on:
11592  * Ext JS Library 1.1.1
11593  * Copyright(c) 2006-2007, Ext JS, LLC.
11594  *
11595  * Originally Released Under LGPL - original licence link has changed is not relivant.
11596  *
11597  * Fork - LGPL
11598  * <script type="text/javascript">
11599  */
11600  
11601 /**
11602  * Global Ajax request class.
11603  * 
11604  * @class Roo.Ajax
11605  * @extends Roo.data.Connection
11606  * @static
11607  * 
11608  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11609  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11610  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11611  * @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)
11612  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11613  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11614  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11615  */
11616 Roo.Ajax = new Roo.data.Connection({
11617     // fix up the docs
11618     /**
11619      * @scope Roo.Ajax
11620      * @type {Boolear} 
11621      */
11622     autoAbort : false,
11623
11624     /**
11625      * Serialize the passed form into a url encoded string
11626      * @scope Roo.Ajax
11627      * @param {String/HTMLElement} form
11628      * @return {String}
11629      */
11630     serializeForm : function(form){
11631         return Roo.lib.Ajax.serializeForm(form);
11632     }
11633 });/*
11634  * Based on:
11635  * Ext JS Library 1.1.1
11636  * Copyright(c) 2006-2007, Ext JS, LLC.
11637  *
11638  * Originally Released Under LGPL - original licence link has changed is not relivant.
11639  *
11640  * Fork - LGPL
11641  * <script type="text/javascript">
11642  */
11643
11644  
11645 /**
11646  * @class Roo.UpdateManager
11647  * @extends Roo.util.Observable
11648  * Provides AJAX-style update for Element object.<br><br>
11649  * Usage:<br>
11650  * <pre><code>
11651  * // Get it from a Roo.Element object
11652  * var el = Roo.get("foo");
11653  * var mgr = el.getUpdateManager();
11654  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11655  * ...
11656  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11657  * <br>
11658  * // or directly (returns the same UpdateManager instance)
11659  * var mgr = new Roo.UpdateManager("myElementId");
11660  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11661  * mgr.on("update", myFcnNeedsToKnow);
11662  * <br>
11663    // short handed call directly from the element object
11664    Roo.get("foo").load({
11665         url: "bar.php",
11666         scripts:true,
11667         params: "for=bar",
11668         text: "Loading Foo..."
11669    });
11670  * </code></pre>
11671  * @constructor
11672  * Create new UpdateManager directly.
11673  * @param {String/HTMLElement/Roo.Element} el The element to update
11674  * @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).
11675  */
11676 Roo.UpdateManager = function(el, forceNew){
11677     el = Roo.get(el);
11678     if(!forceNew && el.updateManager){
11679         return el.updateManager;
11680     }
11681     /**
11682      * The Element object
11683      * @type Roo.Element
11684      */
11685     this.el = el;
11686     /**
11687      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11688      * @type String
11689      */
11690     this.defaultUrl = null;
11691
11692     this.addEvents({
11693         /**
11694          * @event beforeupdate
11695          * Fired before an update is made, return false from your handler and the update is cancelled.
11696          * @param {Roo.Element} el
11697          * @param {String/Object/Function} url
11698          * @param {String/Object} params
11699          */
11700         "beforeupdate": true,
11701         /**
11702          * @event update
11703          * Fired after successful update is made.
11704          * @param {Roo.Element} el
11705          * @param {Object} oResponseObject The response Object
11706          */
11707         "update": true,
11708         /**
11709          * @event failure
11710          * Fired on update failure.
11711          * @param {Roo.Element} el
11712          * @param {Object} oResponseObject The response Object
11713          */
11714         "failure": true
11715     });
11716     var d = Roo.UpdateManager.defaults;
11717     /**
11718      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11719      * @type String
11720      */
11721     this.sslBlankUrl = d.sslBlankUrl;
11722     /**
11723      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11724      * @type Boolean
11725      */
11726     this.disableCaching = d.disableCaching;
11727     /**
11728      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11729      * @type String
11730      */
11731     this.indicatorText = d.indicatorText;
11732     /**
11733      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11734      * @type String
11735      */
11736     this.showLoadIndicator = d.showLoadIndicator;
11737     /**
11738      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11739      * @type Number
11740      */
11741     this.timeout = d.timeout;
11742
11743     /**
11744      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11745      * @type Boolean
11746      */
11747     this.loadScripts = d.loadScripts;
11748
11749     /**
11750      * Transaction object of current executing transaction
11751      */
11752     this.transaction = null;
11753
11754     /**
11755      * @private
11756      */
11757     this.autoRefreshProcId = null;
11758     /**
11759      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11760      * @type Function
11761      */
11762     this.refreshDelegate = this.refresh.createDelegate(this);
11763     /**
11764      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11765      * @type Function
11766      */
11767     this.updateDelegate = this.update.createDelegate(this);
11768     /**
11769      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11770      * @type Function
11771      */
11772     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11773     /**
11774      * @private
11775      */
11776     this.successDelegate = this.processSuccess.createDelegate(this);
11777     /**
11778      * @private
11779      */
11780     this.failureDelegate = this.processFailure.createDelegate(this);
11781
11782     if(!this.renderer){
11783      /**
11784       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11785       */
11786     this.renderer = new Roo.UpdateManager.BasicRenderer();
11787     }
11788     
11789     Roo.UpdateManager.superclass.constructor.call(this);
11790 };
11791
11792 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11793     /**
11794      * Get the Element this UpdateManager is bound to
11795      * @return {Roo.Element} The element
11796      */
11797     getEl : function(){
11798         return this.el;
11799     },
11800     /**
11801      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11802      * @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:
11803 <pre><code>
11804 um.update({<br/>
11805     url: "your-url.php",<br/>
11806     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11807     callback: yourFunction,<br/>
11808     scope: yourObject, //(optional scope)  <br/>
11809     discardUrl: false, <br/>
11810     nocache: false,<br/>
11811     text: "Loading...",<br/>
11812     timeout: 30,<br/>
11813     scripts: false<br/>
11814 });
11815 </code></pre>
11816      * The only required property is url. The optional properties nocache, text and scripts
11817      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11818      * @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}
11819      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11820      * @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.
11821      */
11822     update : function(url, params, callback, discardUrl){
11823         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11824             var method = this.method,
11825                 cfg;
11826             if(typeof url == "object"){ // must be config object
11827                 cfg = url;
11828                 url = cfg.url;
11829                 params = params || cfg.params;
11830                 callback = callback || cfg.callback;
11831                 discardUrl = discardUrl || cfg.discardUrl;
11832                 if(callback && cfg.scope){
11833                     callback = callback.createDelegate(cfg.scope);
11834                 }
11835                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11836                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11837                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11838                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11839                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11840             }
11841             this.showLoading();
11842             if(!discardUrl){
11843                 this.defaultUrl = url;
11844             }
11845             if(typeof url == "function"){
11846                 url = url.call(this);
11847             }
11848
11849             method = method || (params ? "POST" : "GET");
11850             if(method == "GET"){
11851                 url = this.prepareUrl(url);
11852             }
11853
11854             var o = Roo.apply(cfg ||{}, {
11855                 url : url,
11856                 params: params,
11857                 success: this.successDelegate,
11858                 failure: this.failureDelegate,
11859                 callback: undefined,
11860                 timeout: (this.timeout*1000),
11861                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11862             });
11863             Roo.log("updated manager called with timeout of " + o.timeout);
11864             this.transaction = Roo.Ajax.request(o);
11865         }
11866     },
11867
11868     /**
11869      * 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.
11870      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11871      * @param {String/HTMLElement} form The form Id or form element
11872      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11873      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11874      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11875      */
11876     formUpdate : function(form, url, reset, callback){
11877         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11878             if(typeof url == "function"){
11879                 url = url.call(this);
11880             }
11881             form = Roo.getDom(form);
11882             this.transaction = Roo.Ajax.request({
11883                 form: form,
11884                 url:url,
11885                 success: this.successDelegate,
11886                 failure: this.failureDelegate,
11887                 timeout: (this.timeout*1000),
11888                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11889             });
11890             this.showLoading.defer(1, this);
11891         }
11892     },
11893
11894     /**
11895      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11896      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11897      */
11898     refresh : function(callback){
11899         if(this.defaultUrl == null){
11900             return;
11901         }
11902         this.update(this.defaultUrl, null, callback, true);
11903     },
11904
11905     /**
11906      * Set this element to auto refresh.
11907      * @param {Number} interval How often to update (in seconds).
11908      * @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)
11909      * @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}
11910      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11911      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11912      */
11913     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11914         if(refreshNow){
11915             this.update(url || this.defaultUrl, params, callback, true);
11916         }
11917         if(this.autoRefreshProcId){
11918             clearInterval(this.autoRefreshProcId);
11919         }
11920         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11921     },
11922
11923     /**
11924      * Stop auto refresh on this element.
11925      */
11926      stopAutoRefresh : function(){
11927         if(this.autoRefreshProcId){
11928             clearInterval(this.autoRefreshProcId);
11929             delete this.autoRefreshProcId;
11930         }
11931     },
11932
11933     isAutoRefreshing : function(){
11934        return this.autoRefreshProcId ? true : false;
11935     },
11936     /**
11937      * Called to update the element to "Loading" state. Override to perform custom action.
11938      */
11939     showLoading : function(){
11940         if(this.showLoadIndicator){
11941             this.el.update(this.indicatorText);
11942         }
11943     },
11944
11945     /**
11946      * Adds unique parameter to query string if disableCaching = true
11947      * @private
11948      */
11949     prepareUrl : function(url){
11950         if(this.disableCaching){
11951             var append = "_dc=" + (new Date().getTime());
11952             if(url.indexOf("?") !== -1){
11953                 url += "&" + append;
11954             }else{
11955                 url += "?" + append;
11956             }
11957         }
11958         return url;
11959     },
11960
11961     /**
11962      * @private
11963      */
11964     processSuccess : function(response){
11965         this.transaction = null;
11966         if(response.argument.form && response.argument.reset){
11967             try{ // put in try/catch since some older FF releases had problems with this
11968                 response.argument.form.reset();
11969             }catch(e){}
11970         }
11971         if(this.loadScripts){
11972             this.renderer.render(this.el, response, this,
11973                 this.updateComplete.createDelegate(this, [response]));
11974         }else{
11975             this.renderer.render(this.el, response, this);
11976             this.updateComplete(response);
11977         }
11978     },
11979
11980     updateComplete : function(response){
11981         this.fireEvent("update", this.el, response);
11982         if(typeof response.argument.callback == "function"){
11983             response.argument.callback(this.el, true, response);
11984         }
11985     },
11986
11987     /**
11988      * @private
11989      */
11990     processFailure : function(response){
11991         this.transaction = null;
11992         this.fireEvent("failure", this.el, response);
11993         if(typeof response.argument.callback == "function"){
11994             response.argument.callback(this.el, false, response);
11995         }
11996     },
11997
11998     /**
11999      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12000      * @param {Object} renderer The object implementing the render() method
12001      */
12002     setRenderer : function(renderer){
12003         this.renderer = renderer;
12004     },
12005
12006     getRenderer : function(){
12007        return this.renderer;
12008     },
12009
12010     /**
12011      * Set the defaultUrl used for updates
12012      * @param {String/Function} defaultUrl The url or a function to call to get the url
12013      */
12014     setDefaultUrl : function(defaultUrl){
12015         this.defaultUrl = defaultUrl;
12016     },
12017
12018     /**
12019      * Aborts the executing transaction
12020      */
12021     abort : function(){
12022         if(this.transaction){
12023             Roo.Ajax.abort(this.transaction);
12024         }
12025     },
12026
12027     /**
12028      * Returns true if an update is in progress
12029      * @return {Boolean}
12030      */
12031     isUpdating : function(){
12032         if(this.transaction){
12033             return Roo.Ajax.isLoading(this.transaction);
12034         }
12035         return false;
12036     }
12037 });
12038
12039 /**
12040  * @class Roo.UpdateManager.defaults
12041  * @static (not really - but it helps the doc tool)
12042  * The defaults collection enables customizing the default properties of UpdateManager
12043  */
12044    Roo.UpdateManager.defaults = {
12045        /**
12046          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12047          * @type Number
12048          */
12049          timeout : 30,
12050
12051          /**
12052          * True to process scripts by default (Defaults to false).
12053          * @type Boolean
12054          */
12055         loadScripts : false,
12056
12057         /**
12058         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12059         * @type String
12060         */
12061         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12062         /**
12063          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12064          * @type Boolean
12065          */
12066         disableCaching : false,
12067         /**
12068          * Whether to show indicatorText when loading (Defaults to true).
12069          * @type Boolean
12070          */
12071         showLoadIndicator : true,
12072         /**
12073          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12074          * @type String
12075          */
12076         indicatorText : '<div class="loading-indicator">Loading...</div>'
12077    };
12078
12079 /**
12080  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12081  *Usage:
12082  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12083  * @param {String/HTMLElement/Roo.Element} el The element to update
12084  * @param {String} url The url
12085  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12086  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12087  * @static
12088  * @deprecated
12089  * @member Roo.UpdateManager
12090  */
12091 Roo.UpdateManager.updateElement = function(el, url, params, options){
12092     var um = Roo.get(el, true).getUpdateManager();
12093     Roo.apply(um, options);
12094     um.update(url, params, options ? options.callback : null);
12095 };
12096 // alias for backwards compat
12097 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12098 /**
12099  * @class Roo.UpdateManager.BasicRenderer
12100  * Default Content renderer. Updates the elements innerHTML with the responseText.
12101  */
12102 Roo.UpdateManager.BasicRenderer = function(){};
12103
12104 Roo.UpdateManager.BasicRenderer.prototype = {
12105     /**
12106      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12107      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12108      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12109      * @param {Roo.Element} el The element being rendered
12110      * @param {Object} response The YUI Connect response object
12111      * @param {UpdateManager} updateManager The calling update manager
12112      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12113      */
12114      render : function(el, response, updateManager, callback){
12115         el.update(response.responseText, updateManager.loadScripts, callback);
12116     }
12117 };
12118 /*
12119  * Based on:
12120  * Roo JS
12121  * (c)) Alan Knowles
12122  * Licence : LGPL
12123  */
12124
12125
12126 /**
12127  * @class Roo.DomTemplate
12128  * @extends Roo.Template
12129  * An effort at a dom based template engine..
12130  *
12131  * Similar to XTemplate, except it uses dom parsing to create the template..
12132  *
12133  * Supported features:
12134  *
12135  *  Tags:
12136
12137 <pre><code>
12138       {a_variable} - output encoded.
12139       {a_variable.format:("Y-m-d")} - call a method on the variable
12140       {a_variable:raw} - unencoded output
12141       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12142       {a_variable:this.method_on_template(...)} - call a method on the template object.
12143  
12144 </code></pre>
12145  *  The tpl tag:
12146 <pre><code>
12147         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12148         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12149         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12150         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12151   
12152 </code></pre>
12153  *      
12154  */
12155 Roo.DomTemplate = function()
12156 {
12157      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12158      if (this.html) {
12159         this.compile();
12160      }
12161 };
12162
12163
12164 Roo.extend(Roo.DomTemplate, Roo.Template, {
12165     /**
12166      * id counter for sub templates.
12167      */
12168     id : 0,
12169     /**
12170      * flag to indicate if dom parser is inside a pre,
12171      * it will strip whitespace if not.
12172      */
12173     inPre : false,
12174     
12175     /**
12176      * The various sub templates
12177      */
12178     tpls : false,
12179     
12180     
12181     
12182     /**
12183      *
12184      * basic tag replacing syntax
12185      * WORD:WORD()
12186      *
12187      * // you can fake an object call by doing this
12188      *  x.t:(test,tesT) 
12189      * 
12190      */
12191     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12192     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12193     
12194     iterChild : function (node, method) {
12195         
12196         var oldPre = this.inPre;
12197         if (node.tagName == 'PRE') {
12198             this.inPre = true;
12199         }
12200         for( var i = 0; i < node.childNodes.length; i++) {
12201             method.call(this, node.childNodes[i]);
12202         }
12203         this.inPre = oldPre;
12204     },
12205     
12206     
12207     
12208     /**
12209      * compile the template
12210      *
12211      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12212      *
12213      */
12214     compile: function()
12215     {
12216         var s = this.html;
12217         
12218         // covert the html into DOM...
12219         var doc = false;
12220         var div =false;
12221         try {
12222             doc = document.implementation.createHTMLDocument("");
12223             doc.documentElement.innerHTML =   this.html  ;
12224             div = doc.documentElement;
12225         } catch (e) {
12226             // old IE... - nasty -- it causes all sorts of issues.. with
12227             // images getting pulled from server..
12228             div = document.createElement('div');
12229             div.innerHTML = this.html;
12230         }
12231         //doc.documentElement.innerHTML = htmlBody
12232          
12233         
12234         
12235         this.tpls = [];
12236         var _t = this;
12237         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12238         
12239         var tpls = this.tpls;
12240         
12241         // create a top level template from the snippet..
12242         
12243         //Roo.log(div.innerHTML);
12244         
12245         var tpl = {
12246             uid : 'master',
12247             id : this.id++,
12248             attr : false,
12249             value : false,
12250             body : div.innerHTML,
12251             
12252             forCall : false,
12253             execCall : false,
12254             dom : div,
12255             isTop : true
12256             
12257         };
12258         tpls.unshift(tpl);
12259         
12260         
12261         // compile them...
12262         this.tpls = [];
12263         Roo.each(tpls, function(tp){
12264             this.compileTpl(tp);
12265             this.tpls[tp.id] = tp;
12266         }, this);
12267         
12268         this.master = tpls[0];
12269         return this;
12270         
12271         
12272     },
12273     
12274     compileNode : function(node, istop) {
12275         // test for
12276         //Roo.log(node);
12277         
12278         
12279         // skip anything not a tag..
12280         if (node.nodeType != 1) {
12281             if (node.nodeType == 3 && !this.inPre) {
12282                 // reduce white space..
12283                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12284                 
12285             }
12286             return;
12287         }
12288         
12289         var tpl = {
12290             uid : false,
12291             id : false,
12292             attr : false,
12293             value : false,
12294             body : '',
12295             
12296             forCall : false,
12297             execCall : false,
12298             dom : false,
12299             isTop : istop
12300             
12301             
12302         };
12303         
12304         
12305         switch(true) {
12306             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12307             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12308             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12309             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12310             // no default..
12311         }
12312         
12313         
12314         if (!tpl.attr) {
12315             // just itterate children..
12316             this.iterChild(node,this.compileNode);
12317             return;
12318         }
12319         tpl.uid = this.id++;
12320         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12321         node.removeAttribute('roo-'+ tpl.attr);
12322         if (tpl.attr != 'name') {
12323             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12324             node.parentNode.replaceChild(placeholder,  node);
12325         } else {
12326             
12327             var placeholder =  document.createElement('span');
12328             placeholder.className = 'roo-tpl-' + tpl.value;
12329             node.parentNode.replaceChild(placeholder,  node);
12330         }
12331         
12332         // parent now sees '{domtplXXXX}
12333         this.iterChild(node,this.compileNode);
12334         
12335         // we should now have node body...
12336         var div = document.createElement('div');
12337         div.appendChild(node);
12338         tpl.dom = node;
12339         // this has the unfortunate side effect of converting tagged attributes
12340         // eg. href="{...}" into %7C...%7D
12341         // this has been fixed by searching for those combo's although it's a bit hacky..
12342         
12343         
12344         tpl.body = div.innerHTML;
12345         
12346         
12347          
12348         tpl.id = tpl.uid;
12349         switch(tpl.attr) {
12350             case 'for' :
12351                 switch (tpl.value) {
12352                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12353                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12354                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12355                 }
12356                 break;
12357             
12358             case 'exec':
12359                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12360                 break;
12361             
12362             case 'if':     
12363                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12364                 break;
12365             
12366             case 'name':
12367                 tpl.id  = tpl.value; // replace non characters???
12368                 break;
12369             
12370         }
12371         
12372         
12373         this.tpls.push(tpl);
12374         
12375         
12376         
12377     },
12378     
12379     
12380     
12381     
12382     /**
12383      * Compile a segment of the template into a 'sub-template'
12384      *
12385      * 
12386      * 
12387      *
12388      */
12389     compileTpl : function(tpl)
12390     {
12391         var fm = Roo.util.Format;
12392         var useF = this.disableFormats !== true;
12393         
12394         var sep = Roo.isGecko ? "+\n" : ",\n";
12395         
12396         var undef = function(str) {
12397             Roo.debug && Roo.log("Property not found :"  + str);
12398             return '';
12399         };
12400           
12401         //Roo.log(tpl.body);
12402         
12403         
12404         
12405         var fn = function(m, lbrace, name, format, args)
12406         {
12407             //Roo.log("ARGS");
12408             //Roo.log(arguments);
12409             args = args ? args.replace(/\\'/g,"'") : args;
12410             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12411             if (typeof(format) == 'undefined') {
12412                 format =  'htmlEncode'; 
12413             }
12414             if (format == 'raw' ) {
12415                 format = false;
12416             }
12417             
12418             if(name.substr(0, 6) == 'domtpl'){
12419                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12420             }
12421             
12422             // build an array of options to determine if value is undefined..
12423             
12424             // basically get 'xxxx.yyyy' then do
12425             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12426             //    (function () { Roo.log("Property not found"); return ''; })() :
12427             //    ......
12428             
12429             var udef_ar = [];
12430             var lookfor = '';
12431             Roo.each(name.split('.'), function(st) {
12432                 lookfor += (lookfor.length ? '.': '') + st;
12433                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12434             });
12435             
12436             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12437             
12438             
12439             if(format && useF){
12440                 
12441                 args = args ? ',' + args : "";
12442                  
12443                 if(format.substr(0, 5) != "this."){
12444                     format = "fm." + format + '(';
12445                 }else{
12446                     format = 'this.call("'+ format.substr(5) + '", ';
12447                     args = ", values";
12448                 }
12449                 
12450                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12451             }
12452              
12453             if (args && args.length) {
12454                 // called with xxyx.yuu:(test,test)
12455                 // change to ()
12456                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12457             }
12458             // raw.. - :raw modifier..
12459             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12460             
12461         };
12462         var body;
12463         // branched to use + in gecko and [].join() in others
12464         if(Roo.isGecko){
12465             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12466                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12467                     "';};};";
12468         }else{
12469             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12470             body.push(tpl.body.replace(/(\r\n|\n)/g,
12471                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12472             body.push("'].join('');};};");
12473             body = body.join('');
12474         }
12475         
12476         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12477        
12478         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12479         eval(body);
12480         
12481         return this;
12482     },
12483      
12484     /**
12485      * same as applyTemplate, except it's done to one of the subTemplates
12486      * when using named templates, you can do:
12487      *
12488      * var str = pl.applySubTemplate('your-name', values);
12489      *
12490      * 
12491      * @param {Number} id of the template
12492      * @param {Object} values to apply to template
12493      * @param {Object} parent (normaly the instance of this object)
12494      */
12495     applySubTemplate : function(id, values, parent)
12496     {
12497         
12498         
12499         var t = this.tpls[id];
12500         
12501         
12502         try { 
12503             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12504                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12505                 return '';
12506             }
12507         } catch(e) {
12508             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12509             Roo.log(values);
12510           
12511             return '';
12512         }
12513         try { 
12514             
12515             if(t.execCall && t.execCall.call(this, values, parent)){
12516                 return '';
12517             }
12518         } catch(e) {
12519             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12520             Roo.log(values);
12521             return '';
12522         }
12523         
12524         try {
12525             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12526             parent = t.target ? values : parent;
12527             if(t.forCall && vs instanceof Array){
12528                 var buf = [];
12529                 for(var i = 0, len = vs.length; i < len; i++){
12530                     try {
12531                         buf[buf.length] = t.compiled.call(this, vs[i], 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(vs[i]);
12537                     }   
12538                 }
12539                 return buf.join('');
12540             }
12541         } catch (e) {
12542             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12543             Roo.log(values);
12544             return '';
12545         }
12546         try {
12547             return t.compiled.call(this, vs, parent);
12548         } catch (e) {
12549             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12550             Roo.log(e.body);
12551             //Roo.log(t.compiled);
12552             Roo.log(values);
12553             return '';
12554         }
12555     },
12556
12557    
12558
12559     applyTemplate : function(values){
12560         return this.master.compiled.call(this, values, {});
12561         //var s = this.subs;
12562     },
12563
12564     apply : function(){
12565         return this.applyTemplate.apply(this, arguments);
12566     }
12567
12568  });
12569
12570 Roo.DomTemplate.from = function(el){
12571     el = Roo.getDom(el);
12572     return new Roo.Domtemplate(el.value || el.innerHTML);
12573 };/*
12574  * Based on:
12575  * Ext JS Library 1.1.1
12576  * Copyright(c) 2006-2007, Ext JS, LLC.
12577  *
12578  * Originally Released Under LGPL - original licence link has changed is not relivant.
12579  *
12580  * Fork - LGPL
12581  * <script type="text/javascript">
12582  */
12583
12584 /**
12585  * @class Roo.util.DelayedTask
12586  * Provides a convenient method of performing setTimeout where a new
12587  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12588  * You can use this class to buffer
12589  * the keypress events for a certain number of milliseconds, and perform only if they stop
12590  * for that amount of time.
12591  * @constructor The parameters to this constructor serve as defaults and are not required.
12592  * @param {Function} fn (optional) The default function to timeout
12593  * @param {Object} scope (optional) The default scope of that timeout
12594  * @param {Array} args (optional) The default Array of arguments
12595  */
12596 Roo.util.DelayedTask = function(fn, scope, args){
12597     var id = null, d, t;
12598
12599     var call = function(){
12600         var now = new Date().getTime();
12601         if(now - t >= d){
12602             clearInterval(id);
12603             id = null;
12604             fn.apply(scope, args || []);
12605         }
12606     };
12607     /**
12608      * Cancels any pending timeout and queues a new one
12609      * @param {Number} delay The milliseconds to delay
12610      * @param {Function} newFn (optional) Overrides function passed to constructor
12611      * @param {Object} newScope (optional) Overrides scope passed to constructor
12612      * @param {Array} newArgs (optional) Overrides args passed to constructor
12613      */
12614     this.delay = function(delay, newFn, newScope, newArgs){
12615         if(id && delay != d){
12616             this.cancel();
12617         }
12618         d = delay;
12619         t = new Date().getTime();
12620         fn = newFn || fn;
12621         scope = newScope || scope;
12622         args = newArgs || args;
12623         if(!id){
12624             id = setInterval(call, d);
12625         }
12626     };
12627
12628     /**
12629      * Cancel the last queued timeout
12630      */
12631     this.cancel = function(){
12632         if(id){
12633             clearInterval(id);
12634             id = null;
12635         }
12636     };
12637 };/*
12638  * Based on:
12639  * Ext JS Library 1.1.1
12640  * Copyright(c) 2006-2007, Ext JS, LLC.
12641  *
12642  * Originally Released Under LGPL - original licence link has changed is not relivant.
12643  *
12644  * Fork - LGPL
12645  * <script type="text/javascript">
12646  */
12647  
12648  
12649 Roo.util.TaskRunner = function(interval){
12650     interval = interval || 10;
12651     var tasks = [], removeQueue = [];
12652     var id = 0;
12653     var running = false;
12654
12655     var stopThread = function(){
12656         running = false;
12657         clearInterval(id);
12658         id = 0;
12659     };
12660
12661     var startThread = function(){
12662         if(!running){
12663             running = true;
12664             id = setInterval(runTasks, interval);
12665         }
12666     };
12667
12668     var removeTask = function(task){
12669         removeQueue.push(task);
12670         if(task.onStop){
12671             task.onStop();
12672         }
12673     };
12674
12675     var runTasks = function(){
12676         if(removeQueue.length > 0){
12677             for(var i = 0, len = removeQueue.length; i < len; i++){
12678                 tasks.remove(removeQueue[i]);
12679             }
12680             removeQueue = [];
12681             if(tasks.length < 1){
12682                 stopThread();
12683                 return;
12684             }
12685         }
12686         var now = new Date().getTime();
12687         for(var i = 0, len = tasks.length; i < len; ++i){
12688             var t = tasks[i];
12689             var itime = now - t.taskRunTime;
12690             if(t.interval <= itime){
12691                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12692                 t.taskRunTime = now;
12693                 if(rt === false || t.taskRunCount === t.repeat){
12694                     removeTask(t);
12695                     return;
12696                 }
12697             }
12698             if(t.duration && t.duration <= (now - t.taskStartTime)){
12699                 removeTask(t);
12700             }
12701         }
12702     };
12703
12704     /**
12705      * Queues a new task.
12706      * @param {Object} task
12707      */
12708     this.start = function(task){
12709         tasks.push(task);
12710         task.taskStartTime = new Date().getTime();
12711         task.taskRunTime = 0;
12712         task.taskRunCount = 0;
12713         startThread();
12714         return task;
12715     };
12716
12717     this.stop = function(task){
12718         removeTask(task);
12719         return task;
12720     };
12721
12722     this.stopAll = function(){
12723         stopThread();
12724         for(var i = 0, len = tasks.length; i < len; i++){
12725             if(tasks[i].onStop){
12726                 tasks[i].onStop();
12727             }
12728         }
12729         tasks = [];
12730         removeQueue = [];
12731     };
12732 };
12733
12734 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12735  * Based on:
12736  * Ext JS Library 1.1.1
12737  * Copyright(c) 2006-2007, Ext JS, LLC.
12738  *
12739  * Originally Released Under LGPL - original licence link has changed is not relivant.
12740  *
12741  * Fork - LGPL
12742  * <script type="text/javascript">
12743  */
12744
12745  
12746 /**
12747  * @class Roo.util.MixedCollection
12748  * @extends Roo.util.Observable
12749  * A Collection class that maintains both numeric indexes and keys and exposes events.
12750  * @constructor
12751  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12752  * collection (defaults to false)
12753  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12754  * and return the key value for that item.  This is used when available to look up the key on items that
12755  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12756  * equivalent to providing an implementation for the {@link #getKey} method.
12757  */
12758 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12759     this.items = [];
12760     this.map = {};
12761     this.keys = [];
12762     this.length = 0;
12763     this.addEvents({
12764         /**
12765          * @event clear
12766          * Fires when the collection is cleared.
12767          */
12768         "clear" : true,
12769         /**
12770          * @event add
12771          * Fires when an item is added to the collection.
12772          * @param {Number} index The index at which the item was added.
12773          * @param {Object} o The item added.
12774          * @param {String} key The key associated with the added item.
12775          */
12776         "add" : true,
12777         /**
12778          * @event replace
12779          * Fires when an item is replaced in the collection.
12780          * @param {String} key he key associated with the new added.
12781          * @param {Object} old The item being replaced.
12782          * @param {Object} new The new item.
12783          */
12784         "replace" : true,
12785         /**
12786          * @event remove
12787          * Fires when an item is removed from the collection.
12788          * @param {Object} o The item being removed.
12789          * @param {String} key (optional) The key associated with the removed item.
12790          */
12791         "remove" : true,
12792         "sort" : true
12793     });
12794     this.allowFunctions = allowFunctions === true;
12795     if(keyFn){
12796         this.getKey = keyFn;
12797     }
12798     Roo.util.MixedCollection.superclass.constructor.call(this);
12799 };
12800
12801 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12802     allowFunctions : false,
12803     
12804 /**
12805  * Adds an item to the collection.
12806  * @param {String} key The key to associate with the item
12807  * @param {Object} o The item to add.
12808  * @return {Object} The item added.
12809  */
12810     add : function(key, o){
12811         if(arguments.length == 1){
12812             o = arguments[0];
12813             key = this.getKey(o);
12814         }
12815         if(typeof key == "undefined" || key === null){
12816             this.length++;
12817             this.items.push(o);
12818             this.keys.push(null);
12819         }else{
12820             var old = this.map[key];
12821             if(old){
12822                 return this.replace(key, o);
12823             }
12824             this.length++;
12825             this.items.push(o);
12826             this.map[key] = o;
12827             this.keys.push(key);
12828         }
12829         this.fireEvent("add", this.length-1, o, key);
12830         return o;
12831     },
12832        
12833 /**
12834   * MixedCollection has a generic way to fetch keys if you implement getKey.
12835 <pre><code>
12836 // normal way
12837 var mc = new Roo.util.MixedCollection();
12838 mc.add(someEl.dom.id, someEl);
12839 mc.add(otherEl.dom.id, otherEl);
12840 //and so on
12841
12842 // using getKey
12843 var mc = new Roo.util.MixedCollection();
12844 mc.getKey = function(el){
12845    return el.dom.id;
12846 };
12847 mc.add(someEl);
12848 mc.add(otherEl);
12849
12850 // or via the constructor
12851 var mc = new Roo.util.MixedCollection(false, function(el){
12852    return el.dom.id;
12853 });
12854 mc.add(someEl);
12855 mc.add(otherEl);
12856 </code></pre>
12857  * @param o {Object} The item for which to find the key.
12858  * @return {Object} The key for the passed item.
12859  */
12860     getKey : function(o){
12861          return o.id; 
12862     },
12863    
12864 /**
12865  * Replaces an item in the collection.
12866  * @param {String} key The key associated with the item to replace, or the item to replace.
12867  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12868  * @return {Object}  The new item.
12869  */
12870     replace : function(key, o){
12871         if(arguments.length == 1){
12872             o = arguments[0];
12873             key = this.getKey(o);
12874         }
12875         var old = this.item(key);
12876         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12877              return this.add(key, o);
12878         }
12879         var index = this.indexOfKey(key);
12880         this.items[index] = o;
12881         this.map[key] = o;
12882         this.fireEvent("replace", key, old, o);
12883         return o;
12884     },
12885    
12886 /**
12887  * Adds all elements of an Array or an Object to the collection.
12888  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12889  * an Array of values, each of which are added to the collection.
12890  */
12891     addAll : function(objs){
12892         if(arguments.length > 1 || objs instanceof Array){
12893             var args = arguments.length > 1 ? arguments : objs;
12894             for(var i = 0, len = args.length; i < len; i++){
12895                 this.add(args[i]);
12896             }
12897         }else{
12898             for(var key in objs){
12899                 if(this.allowFunctions || typeof objs[key] != "function"){
12900                     this.add(key, objs[key]);
12901                 }
12902             }
12903         }
12904     },
12905    
12906 /**
12907  * Executes the specified function once for every item in the collection, passing each
12908  * item as the first and only parameter. returning false from the function will stop the iteration.
12909  * @param {Function} fn The function to execute for each item.
12910  * @param {Object} scope (optional) The scope in which to execute the function.
12911  */
12912     each : function(fn, scope){
12913         var items = [].concat(this.items); // each safe for removal
12914         for(var i = 0, len = items.length; i < len; i++){
12915             if(fn.call(scope || items[i], items[i], i, len) === false){
12916                 break;
12917             }
12918         }
12919     },
12920    
12921 /**
12922  * Executes the specified function once for every key in the collection, passing each
12923  * key, and its associated item as the first two parameters.
12924  * @param {Function} fn The function to execute for each item.
12925  * @param {Object} scope (optional) The scope in which to execute the function.
12926  */
12927     eachKey : function(fn, scope){
12928         for(var i = 0, len = this.keys.length; i < len; i++){
12929             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12930         }
12931     },
12932    
12933 /**
12934  * Returns the first item in the collection which elicits a true return value from the
12935  * passed selection function.
12936  * @param {Function} fn The selection function to execute for each item.
12937  * @param {Object} scope (optional) The scope in which to execute the function.
12938  * @return {Object} The first item in the collection which returned true from the selection function.
12939  */
12940     find : function(fn, scope){
12941         for(var i = 0, len = this.items.length; i < len; i++){
12942             if(fn.call(scope || window, this.items[i], this.keys[i])){
12943                 return this.items[i];
12944             }
12945         }
12946         return null;
12947     },
12948    
12949 /**
12950  * Inserts an item at the specified index in the collection.
12951  * @param {Number} index The index to insert the item at.
12952  * @param {String} key The key to associate with the new item, or the item itself.
12953  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12954  * @return {Object} The item inserted.
12955  */
12956     insert : function(index, key, o){
12957         if(arguments.length == 2){
12958             o = arguments[1];
12959             key = this.getKey(o);
12960         }
12961         if(index >= this.length){
12962             return this.add(key, o);
12963         }
12964         this.length++;
12965         this.items.splice(index, 0, o);
12966         if(typeof key != "undefined" && key != null){
12967             this.map[key] = o;
12968         }
12969         this.keys.splice(index, 0, key);
12970         this.fireEvent("add", index, o, key);
12971         return o;
12972     },
12973    
12974 /**
12975  * Removed an item from the collection.
12976  * @param {Object} o The item to remove.
12977  * @return {Object} The item removed.
12978  */
12979     remove : function(o){
12980         return this.removeAt(this.indexOf(o));
12981     },
12982    
12983 /**
12984  * Remove an item from a specified index in the collection.
12985  * @param {Number} index The index within the collection of the item to remove.
12986  */
12987     removeAt : function(index){
12988         if(index < this.length && index >= 0){
12989             this.length--;
12990             var o = this.items[index];
12991             this.items.splice(index, 1);
12992             var key = this.keys[index];
12993             if(typeof key != "undefined"){
12994                 delete this.map[key];
12995             }
12996             this.keys.splice(index, 1);
12997             this.fireEvent("remove", o, key);
12998         }
12999     },
13000    
13001 /**
13002  * Removed an item associated with the passed key fom the collection.
13003  * @param {String} key The key of the item to remove.
13004  */
13005     removeKey : function(key){
13006         return this.removeAt(this.indexOfKey(key));
13007     },
13008    
13009 /**
13010  * Returns the number of items in the collection.
13011  * @return {Number} the number of items in the collection.
13012  */
13013     getCount : function(){
13014         return this.length; 
13015     },
13016    
13017 /**
13018  * Returns index within the collection of the passed Object.
13019  * @param {Object} o The item to find the index of.
13020  * @return {Number} index of the item.
13021  */
13022     indexOf : function(o){
13023         if(!this.items.indexOf){
13024             for(var i = 0, len = this.items.length; i < len; i++){
13025                 if(this.items[i] == o) return i;
13026             }
13027             return -1;
13028         }else{
13029             return this.items.indexOf(o);
13030         }
13031     },
13032    
13033 /**
13034  * Returns index within the collection of the passed key.
13035  * @param {String} key The key to find the index of.
13036  * @return {Number} index of the key.
13037  */
13038     indexOfKey : function(key){
13039         if(!this.keys.indexOf){
13040             for(var i = 0, len = this.keys.length; i < len; i++){
13041                 if(this.keys[i] == key) return i;
13042             }
13043             return -1;
13044         }else{
13045             return this.keys.indexOf(key);
13046         }
13047     },
13048    
13049 /**
13050  * Returns the item associated with the passed key OR index. Key has priority over index.
13051  * @param {String/Number} key The key or index of the item.
13052  * @return {Object} The item associated with the passed key.
13053  */
13054     item : function(key){
13055         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13056         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13057     },
13058     
13059 /**
13060  * Returns the item at the specified index.
13061  * @param {Number} index The index of the item.
13062  * @return {Object}
13063  */
13064     itemAt : function(index){
13065         return this.items[index];
13066     },
13067     
13068 /**
13069  * Returns the item associated with the passed key.
13070  * @param {String/Number} key The key of the item.
13071  * @return {Object} The item associated with the passed key.
13072  */
13073     key : function(key){
13074         return this.map[key];
13075     },
13076    
13077 /**
13078  * Returns true if the collection contains the passed Object as an item.
13079  * @param {Object} o  The Object to look for in the collection.
13080  * @return {Boolean} True if the collection contains the Object as an item.
13081  */
13082     contains : function(o){
13083         return this.indexOf(o) != -1;
13084     },
13085    
13086 /**
13087  * Returns true if the collection contains the passed Object as a key.
13088  * @param {String} key The key to look for in the collection.
13089  * @return {Boolean} True if the collection contains the Object as a key.
13090  */
13091     containsKey : function(key){
13092         return typeof this.map[key] != "undefined";
13093     },
13094    
13095 /**
13096  * Removes all items from the collection.
13097  */
13098     clear : function(){
13099         this.length = 0;
13100         this.items = [];
13101         this.keys = [];
13102         this.map = {};
13103         this.fireEvent("clear");
13104     },
13105    
13106 /**
13107  * Returns the first item in the collection.
13108  * @return {Object} the first item in the collection..
13109  */
13110     first : function(){
13111         return this.items[0]; 
13112     },
13113    
13114 /**
13115  * Returns the last item in the collection.
13116  * @return {Object} the last item in the collection..
13117  */
13118     last : function(){
13119         return this.items[this.length-1];   
13120     },
13121     
13122     _sort : function(property, dir, fn){
13123         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13124         fn = fn || function(a, b){
13125             return a-b;
13126         };
13127         var c = [], k = this.keys, items = this.items;
13128         for(var i = 0, len = items.length; i < len; i++){
13129             c[c.length] = {key: k[i], value: items[i], index: i};
13130         }
13131         c.sort(function(a, b){
13132             var v = fn(a[property], b[property]) * dsc;
13133             if(v == 0){
13134                 v = (a.index < b.index ? -1 : 1);
13135             }
13136             return v;
13137         });
13138         for(var i = 0, len = c.length; i < len; i++){
13139             items[i] = c[i].value;
13140             k[i] = c[i].key;
13141         }
13142         this.fireEvent("sort", this);
13143     },
13144     
13145     /**
13146      * Sorts this collection with the passed comparison function
13147      * @param {String} direction (optional) "ASC" or "DESC"
13148      * @param {Function} fn (optional) comparison function
13149      */
13150     sort : function(dir, fn){
13151         this._sort("value", dir, fn);
13152     },
13153     
13154     /**
13155      * Sorts this collection by keys
13156      * @param {String} direction (optional) "ASC" or "DESC"
13157      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13158      */
13159     keySort : function(dir, fn){
13160         this._sort("key", dir, fn || function(a, b){
13161             return String(a).toUpperCase()-String(b).toUpperCase();
13162         });
13163     },
13164     
13165     /**
13166      * Returns a range of items in this collection
13167      * @param {Number} startIndex (optional) defaults to 0
13168      * @param {Number} endIndex (optional) default to the last item
13169      * @return {Array} An array of items
13170      */
13171     getRange : function(start, end){
13172         var items = this.items;
13173         if(items.length < 1){
13174             return [];
13175         }
13176         start = start || 0;
13177         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13178         var r = [];
13179         if(start <= end){
13180             for(var i = start; i <= end; i++) {
13181                     r[r.length] = items[i];
13182             }
13183         }else{
13184             for(var i = start; i >= end; i--) {
13185                     r[r.length] = items[i];
13186             }
13187         }
13188         return r;
13189     },
13190         
13191     /**
13192      * Filter the <i>objects</i> in this collection by a specific property. 
13193      * Returns a new collection that has been filtered.
13194      * @param {String} property A property on your objects
13195      * @param {String/RegExp} value Either string that the property values 
13196      * should start with or a RegExp to test against the property
13197      * @return {MixedCollection} The new filtered collection
13198      */
13199     filter : function(property, value){
13200         if(!value.exec){ // not a regex
13201             value = String(value);
13202             if(value.length == 0){
13203                 return this.clone();
13204             }
13205             value = new RegExp("^" + Roo.escapeRe(value), "i");
13206         }
13207         return this.filterBy(function(o){
13208             return o && value.test(o[property]);
13209         });
13210         },
13211     
13212     /**
13213      * Filter by a function. * Returns a new collection that has been filtered.
13214      * The passed function will be called with each 
13215      * object in the collection. If the function returns true, the value is included 
13216      * otherwise it is filtered.
13217      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13218      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13219      * @return {MixedCollection} The new filtered collection
13220      */
13221     filterBy : function(fn, scope){
13222         var r = new Roo.util.MixedCollection();
13223         r.getKey = this.getKey;
13224         var k = this.keys, it = this.items;
13225         for(var i = 0, len = it.length; i < len; i++){
13226             if(fn.call(scope||this, it[i], k[i])){
13227                                 r.add(k[i], it[i]);
13228                         }
13229         }
13230         return r;
13231     },
13232     
13233     /**
13234      * Creates a duplicate of this collection
13235      * @return {MixedCollection}
13236      */
13237     clone : function(){
13238         var r = new Roo.util.MixedCollection();
13239         var k = this.keys, it = this.items;
13240         for(var i = 0, len = it.length; i < len; i++){
13241             r.add(k[i], it[i]);
13242         }
13243         r.getKey = this.getKey;
13244         return r;
13245     }
13246 });
13247 /**
13248  * Returns the item associated with the passed key or index.
13249  * @method
13250  * @param {String/Number} key The key or index of the item.
13251  * @return {Object} The item associated with the passed key.
13252  */
13253 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13254  * Based on:
13255  * Ext JS Library 1.1.1
13256  * Copyright(c) 2006-2007, Ext JS, LLC.
13257  *
13258  * Originally Released Under LGPL - original licence link has changed is not relivant.
13259  *
13260  * Fork - LGPL
13261  * <script type="text/javascript">
13262  */
13263 /**
13264  * @class Roo.util.JSON
13265  * Modified version of Douglas Crockford"s json.js that doesn"t
13266  * mess with the Object prototype 
13267  * http://www.json.org/js.html
13268  * @singleton
13269  */
13270 Roo.util.JSON = new (function(){
13271     var useHasOwn = {}.hasOwnProperty ? true : false;
13272     
13273     // crashes Safari in some instances
13274     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13275     
13276     var pad = function(n) {
13277         return n < 10 ? "0" + n : n;
13278     };
13279     
13280     var m = {
13281         "\b": '\\b',
13282         "\t": '\\t',
13283         "\n": '\\n',
13284         "\f": '\\f',
13285         "\r": '\\r',
13286         '"' : '\\"',
13287         "\\": '\\\\'
13288     };
13289
13290     var encodeString = function(s){
13291         if (/["\\\x00-\x1f]/.test(s)) {
13292             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13293                 var c = m[b];
13294                 if(c){
13295                     return c;
13296                 }
13297                 c = b.charCodeAt();
13298                 return "\\u00" +
13299                     Math.floor(c / 16).toString(16) +
13300                     (c % 16).toString(16);
13301             }) + '"';
13302         }
13303         return '"' + s + '"';
13304     };
13305     
13306     var encodeArray = function(o){
13307         var a = ["["], b, i, l = o.length, v;
13308             for (i = 0; i < l; i += 1) {
13309                 v = o[i];
13310                 switch (typeof v) {
13311                     case "undefined":
13312                     case "function":
13313                     case "unknown":
13314                         break;
13315                     default:
13316                         if (b) {
13317                             a.push(',');
13318                         }
13319                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13320                         b = true;
13321                 }
13322             }
13323             a.push("]");
13324             return a.join("");
13325     };
13326     
13327     var encodeDate = function(o){
13328         return '"' + o.getFullYear() + "-" +
13329                 pad(o.getMonth() + 1) + "-" +
13330                 pad(o.getDate()) + "T" +
13331                 pad(o.getHours()) + ":" +
13332                 pad(o.getMinutes()) + ":" +
13333                 pad(o.getSeconds()) + '"';
13334     };
13335     
13336     /**
13337      * Encodes an Object, Array or other value
13338      * @param {Mixed} o The variable to encode
13339      * @return {String} The JSON string
13340      */
13341     this.encode = function(o)
13342     {
13343         // should this be extended to fully wrap stringify..
13344         
13345         if(typeof o == "undefined" || o === null){
13346             return "null";
13347         }else if(o instanceof Array){
13348             return encodeArray(o);
13349         }else if(o instanceof Date){
13350             return encodeDate(o);
13351         }else if(typeof o == "string"){
13352             return encodeString(o);
13353         }else if(typeof o == "number"){
13354             return isFinite(o) ? String(o) : "null";
13355         }else if(typeof o == "boolean"){
13356             return String(o);
13357         }else {
13358             var a = ["{"], b, i, v;
13359             for (i in o) {
13360                 if(!useHasOwn || o.hasOwnProperty(i)) {
13361                     v = o[i];
13362                     switch (typeof v) {
13363                     case "undefined":
13364                     case "function":
13365                     case "unknown":
13366                         break;
13367                     default:
13368                         if(b){
13369                             a.push(',');
13370                         }
13371                         a.push(this.encode(i), ":",
13372                                 v === null ? "null" : this.encode(v));
13373                         b = true;
13374                     }
13375                 }
13376             }
13377             a.push("}");
13378             return a.join("");
13379         }
13380     };
13381     
13382     /**
13383      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13384      * @param {String} json The JSON string
13385      * @return {Object} The resulting object
13386      */
13387     this.decode = function(json){
13388         
13389         return  /** eval:var:json */ eval("(" + json + ')');
13390     };
13391 })();
13392 /** 
13393  * Shorthand for {@link Roo.util.JSON#encode}
13394  * @member Roo encode 
13395  * @method */
13396 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13397 /** 
13398  * Shorthand for {@link Roo.util.JSON#decode}
13399  * @member Roo decode 
13400  * @method */
13401 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13402 /*
13403  * Based on:
13404  * Ext JS Library 1.1.1
13405  * Copyright(c) 2006-2007, Ext JS, LLC.
13406  *
13407  * Originally Released Under LGPL - original licence link has changed is not relivant.
13408  *
13409  * Fork - LGPL
13410  * <script type="text/javascript">
13411  */
13412  
13413 /**
13414  * @class Roo.util.Format
13415  * Reusable data formatting functions
13416  * @singleton
13417  */
13418 Roo.util.Format = function(){
13419     var trimRe = /^\s+|\s+$/g;
13420     return {
13421         /**
13422          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13423          * @param {String} value The string to truncate
13424          * @param {Number} length The maximum length to allow before truncating
13425          * @return {String} The converted text
13426          */
13427         ellipsis : function(value, len){
13428             if(value && value.length > len){
13429                 return value.substr(0, len-3)+"...";
13430             }
13431             return value;
13432         },
13433
13434         /**
13435          * Checks a reference and converts it to empty string if it is undefined
13436          * @param {Mixed} value Reference to check
13437          * @return {Mixed} Empty string if converted, otherwise the original value
13438          */
13439         undef : function(value){
13440             return typeof value != "undefined" ? value : "";
13441         },
13442
13443         /**
13444          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13445          * @param {String} value The string to encode
13446          * @return {String} The encoded text
13447          */
13448         htmlEncode : function(value){
13449             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13450         },
13451
13452         /**
13453          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13454          * @param {String} value The string to decode
13455          * @return {String} The decoded text
13456          */
13457         htmlDecode : function(value){
13458             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13459         },
13460
13461         /**
13462          * Trims any whitespace from either side of a string
13463          * @param {String} value The text to trim
13464          * @return {String} The trimmed text
13465          */
13466         trim : function(value){
13467             return String(value).replace(trimRe, "");
13468         },
13469
13470         /**
13471          * Returns a substring from within an original string
13472          * @param {String} value The original text
13473          * @param {Number} start The start index of the substring
13474          * @param {Number} length The length of the substring
13475          * @return {String} The substring
13476          */
13477         substr : function(value, start, length){
13478             return String(value).substr(start, length);
13479         },
13480
13481         /**
13482          * Converts a string to all lower case letters
13483          * @param {String} value The text to convert
13484          * @return {String} The converted text
13485          */
13486         lowercase : function(value){
13487             return String(value).toLowerCase();
13488         },
13489
13490         /**
13491          * Converts a string to all upper case letters
13492          * @param {String} value The text to convert
13493          * @return {String} The converted text
13494          */
13495         uppercase : function(value){
13496             return String(value).toUpperCase();
13497         },
13498
13499         /**
13500          * Converts the first character only of a string to upper case
13501          * @param {String} value The text to convert
13502          * @return {String} The converted text
13503          */
13504         capitalize : function(value){
13505             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13506         },
13507
13508         // private
13509         call : function(value, fn){
13510             if(arguments.length > 2){
13511                 var args = Array.prototype.slice.call(arguments, 2);
13512                 args.unshift(value);
13513                  
13514                 return /** eval:var:value */  eval(fn).apply(window, args);
13515             }else{
13516                 /** eval:var:value */
13517                 return /** eval:var:value */ eval(fn).call(window, value);
13518             }
13519         },
13520
13521        
13522         /**
13523          * safer version of Math.toFixed..??/
13524          * @param {Number/String} value The numeric value to format
13525          * @param {Number/String} value Decimal places 
13526          * @return {String} The formatted currency string
13527          */
13528         toFixed : function(v, n)
13529         {
13530             // why not use to fixed - precision is buggered???
13531             if (!n) {
13532                 return Math.round(v-0);
13533             }
13534             var fact = Math.pow(10,n+1);
13535             v = (Math.round((v-0)*fact))/fact;
13536             var z = (''+fact).substring(2);
13537             if (v == Math.floor(v)) {
13538                 return Math.floor(v) + '.' + z;
13539             }
13540             
13541             // now just padd decimals..
13542             var ps = String(v).split('.');
13543             var fd = (ps[1] + z);
13544             var r = fd.substring(0,n); 
13545             var rm = fd.substring(n); 
13546             if (rm < 5) {
13547                 return ps[0] + '.' + r;
13548             }
13549             r*=1; // turn it into a number;
13550             r++;
13551             if (String(r).length != n) {
13552                 ps[0]*=1;
13553                 ps[0]++;
13554                 r = String(r).substring(1); // chop the end off.
13555             }
13556             
13557             return ps[0] + '.' + r;
13558              
13559         },
13560         
13561         /**
13562          * Format a number as US currency
13563          * @param {Number/String} value The numeric value to format
13564          * @return {String} The formatted currency string
13565          */
13566         usMoney : function(v){
13567             return '$' + Roo.util.Format.number(v);
13568         },
13569         
13570         /**
13571          * Format a number
13572          * eventually this should probably emulate php's number_format
13573          * @param {Number/String} value The numeric value to format
13574          * @param {Number} decimals number of decimal places
13575          * @return {String} The formatted currency string
13576          */
13577         number : function(v,decimals)
13578         {
13579             // multiply and round.
13580             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13581             var mul = Math.pow(10, decimals);
13582             var zero = String(mul).substring(1);
13583             v = (Math.round((v-0)*mul))/mul;
13584             
13585             // if it's '0' number.. then
13586             
13587             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13588             v = String(v);
13589             var ps = v.split('.');
13590             var whole = ps[0];
13591             
13592             
13593             var r = /(\d+)(\d{3})/;
13594             // add comma's
13595             while (r.test(whole)) {
13596                 whole = whole.replace(r, '$1' + ',' + '$2');
13597             }
13598             
13599             
13600             var sub = ps[1] ?
13601                     // has decimals..
13602                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13603                     // does not have decimals
13604                     (decimals ? ('.' + zero) : '');
13605             
13606             
13607             return whole + sub ;
13608         },
13609         
13610         /**
13611          * Parse a value into a formatted date using the specified format pattern.
13612          * @param {Mixed} value The value to format
13613          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13614          * @return {String} The formatted date string
13615          */
13616         date : function(v, format){
13617             if(!v){
13618                 return "";
13619             }
13620             if(!(v instanceof Date)){
13621                 v = new Date(Date.parse(v));
13622             }
13623             return v.dateFormat(format || Roo.util.Format.defaults.date);
13624         },
13625
13626         /**
13627          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13628          * @param {String} format Any valid date format string
13629          * @return {Function} The date formatting function
13630          */
13631         dateRenderer : function(format){
13632             return function(v){
13633                 return Roo.util.Format.date(v, format);  
13634             };
13635         },
13636
13637         // private
13638         stripTagsRE : /<\/?[^>]+>/gi,
13639         
13640         /**
13641          * Strips all HTML tags
13642          * @param {Mixed} value The text from which to strip tags
13643          * @return {String} The stripped text
13644          */
13645         stripTags : function(v){
13646             return !v ? v : String(v).replace(this.stripTagsRE, "");
13647         }
13648     };
13649 }();
13650 Roo.util.Format.defaults = {
13651     date : 'd/M/Y'
13652 };/*
13653  * Based on:
13654  * Ext JS Library 1.1.1
13655  * Copyright(c) 2006-2007, Ext JS, LLC.
13656  *
13657  * Originally Released Under LGPL - original licence link has changed is not relivant.
13658  *
13659  * Fork - LGPL
13660  * <script type="text/javascript">
13661  */
13662
13663
13664  
13665
13666 /**
13667  * @class Roo.MasterTemplate
13668  * @extends Roo.Template
13669  * Provides a template that can have child templates. The syntax is:
13670 <pre><code>
13671 var t = new Roo.MasterTemplate(
13672         '&lt;select name="{name}"&gt;',
13673                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13674         '&lt;/select&gt;'
13675 );
13676 t.add('options', {value: 'foo', text: 'bar'});
13677 // or you can add multiple child elements in one shot
13678 t.addAll('options', [
13679     {value: 'foo', text: 'bar'},
13680     {value: 'foo2', text: 'bar2'},
13681     {value: 'foo3', text: 'bar3'}
13682 ]);
13683 // then append, applying the master template values
13684 t.append('my-form', {name: 'my-select'});
13685 </code></pre>
13686 * A name attribute for the child template is not required if you have only one child
13687 * template or you want to refer to them by index.
13688  */
13689 Roo.MasterTemplate = function(){
13690     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13691     this.originalHtml = this.html;
13692     var st = {};
13693     var m, re = this.subTemplateRe;
13694     re.lastIndex = 0;
13695     var subIndex = 0;
13696     while(m = re.exec(this.html)){
13697         var name = m[1], content = m[2];
13698         st[subIndex] = {
13699             name: name,
13700             index: subIndex,
13701             buffer: [],
13702             tpl : new Roo.Template(content)
13703         };
13704         if(name){
13705             st[name] = st[subIndex];
13706         }
13707         st[subIndex].tpl.compile();
13708         st[subIndex].tpl.call = this.call.createDelegate(this);
13709         subIndex++;
13710     }
13711     this.subCount = subIndex;
13712     this.subs = st;
13713 };
13714 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13715     /**
13716     * The regular expression used to match sub templates
13717     * @type RegExp
13718     * @property
13719     */
13720     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13721
13722     /**
13723      * Applies the passed values to a child template.
13724      * @param {String/Number} name (optional) The name or index of the child template
13725      * @param {Array/Object} values The values to be applied to the template
13726      * @return {MasterTemplate} this
13727      */
13728      add : function(name, values){
13729         if(arguments.length == 1){
13730             values = arguments[0];
13731             name = 0;
13732         }
13733         var s = this.subs[name];
13734         s.buffer[s.buffer.length] = s.tpl.apply(values);
13735         return this;
13736     },
13737
13738     /**
13739      * Applies all the passed values to a child template.
13740      * @param {String/Number} name (optional) The name or index of the child template
13741      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13742      * @param {Boolean} reset (optional) True to reset the template first
13743      * @return {MasterTemplate} this
13744      */
13745     fill : function(name, values, reset){
13746         var a = arguments;
13747         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13748             values = a[0];
13749             name = 0;
13750             reset = a[1];
13751         }
13752         if(reset){
13753             this.reset();
13754         }
13755         for(var i = 0, len = values.length; i < len; i++){
13756             this.add(name, values[i]);
13757         }
13758         return this;
13759     },
13760
13761     /**
13762      * Resets the template for reuse
13763      * @return {MasterTemplate} this
13764      */
13765      reset : function(){
13766         var s = this.subs;
13767         for(var i = 0; i < this.subCount; i++){
13768             s[i].buffer = [];
13769         }
13770         return this;
13771     },
13772
13773     applyTemplate : function(values){
13774         var s = this.subs;
13775         var replaceIndex = -1;
13776         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13777             return s[++replaceIndex].buffer.join("");
13778         });
13779         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13780     },
13781
13782     apply : function(){
13783         return this.applyTemplate.apply(this, arguments);
13784     },
13785
13786     compile : function(){return this;}
13787 });
13788
13789 /**
13790  * Alias for fill().
13791  * @method
13792  */
13793 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13794  /**
13795  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13796  * var tpl = Roo.MasterTemplate.from('element-id');
13797  * @param {String/HTMLElement} el
13798  * @param {Object} config
13799  * @static
13800  */
13801 Roo.MasterTemplate.from = function(el, config){
13802     el = Roo.getDom(el);
13803     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13804 };/*
13805  * Based on:
13806  * Ext JS Library 1.1.1
13807  * Copyright(c) 2006-2007, Ext JS, LLC.
13808  *
13809  * Originally Released Under LGPL - original licence link has changed is not relivant.
13810  *
13811  * Fork - LGPL
13812  * <script type="text/javascript">
13813  */
13814
13815  
13816 /**
13817  * @class Roo.util.CSS
13818  * Utility class for manipulating CSS rules
13819  * @singleton
13820  */
13821 Roo.util.CSS = function(){
13822         var rules = null;
13823         var doc = document;
13824
13825     var camelRe = /(-[a-z])/gi;
13826     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13827
13828    return {
13829    /**
13830     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13831     * tag and appended to the HEAD of the document.
13832     * @param {String|Object} cssText The text containing the css rules
13833     * @param {String} id An id to add to the stylesheet for later removal
13834     * @return {StyleSheet}
13835     */
13836     createStyleSheet : function(cssText, id){
13837         var ss;
13838         var head = doc.getElementsByTagName("head")[0];
13839         var nrules = doc.createElement("style");
13840         nrules.setAttribute("type", "text/css");
13841         if(id){
13842             nrules.setAttribute("id", id);
13843         }
13844         if (typeof(cssText) != 'string') {
13845             // support object maps..
13846             // not sure if this a good idea.. 
13847             // perhaps it should be merged with the general css handling
13848             // and handle js style props.
13849             var cssTextNew = [];
13850             for(var n in cssText) {
13851                 var citems = [];
13852                 for(var k in cssText[n]) {
13853                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13854                 }
13855                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13856                 
13857             }
13858             cssText = cssTextNew.join("\n");
13859             
13860         }
13861        
13862        
13863        if(Roo.isIE){
13864            head.appendChild(nrules);
13865            ss = nrules.styleSheet;
13866            ss.cssText = cssText;
13867        }else{
13868            try{
13869                 nrules.appendChild(doc.createTextNode(cssText));
13870            }catch(e){
13871                nrules.cssText = cssText; 
13872            }
13873            head.appendChild(nrules);
13874            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13875        }
13876        this.cacheStyleSheet(ss);
13877        return ss;
13878    },
13879
13880    /**
13881     * Removes a style or link tag by id
13882     * @param {String} id The id of the tag
13883     */
13884    removeStyleSheet : function(id){
13885        var existing = doc.getElementById(id);
13886        if(existing){
13887            existing.parentNode.removeChild(existing);
13888        }
13889    },
13890
13891    /**
13892     * Dynamically swaps an existing stylesheet reference for a new one
13893     * @param {String} id The id of an existing link tag to remove
13894     * @param {String} url The href of the new stylesheet to include
13895     */
13896    swapStyleSheet : function(id, url){
13897        this.removeStyleSheet(id);
13898        var ss = doc.createElement("link");
13899        ss.setAttribute("rel", "stylesheet");
13900        ss.setAttribute("type", "text/css");
13901        ss.setAttribute("id", id);
13902        ss.setAttribute("href", url);
13903        doc.getElementsByTagName("head")[0].appendChild(ss);
13904    },
13905    
13906    /**
13907     * Refresh the rule cache if you have dynamically added stylesheets
13908     * @return {Object} An object (hash) of rules indexed by selector
13909     */
13910    refreshCache : function(){
13911        return this.getRules(true);
13912    },
13913
13914    // private
13915    cacheStyleSheet : function(stylesheet){
13916        if(!rules){
13917            rules = {};
13918        }
13919        try{// try catch for cross domain access issue
13920            var ssRules = stylesheet.cssRules || stylesheet.rules;
13921            for(var j = ssRules.length-1; j >= 0; --j){
13922                rules[ssRules[j].selectorText] = ssRules[j];
13923            }
13924        }catch(e){}
13925    },
13926    
13927    /**
13928     * Gets all css rules for the document
13929     * @param {Boolean} refreshCache true to refresh the internal cache
13930     * @return {Object} An object (hash) of rules indexed by selector
13931     */
13932    getRules : function(refreshCache){
13933                 if(rules == null || refreshCache){
13934                         rules = {};
13935                         var ds = doc.styleSheets;
13936                         for(var i =0, len = ds.length; i < len; i++){
13937                             try{
13938                         this.cacheStyleSheet(ds[i]);
13939                     }catch(e){} 
13940                 }
13941                 }
13942                 return rules;
13943         },
13944         
13945         /**
13946     * Gets an an individual CSS rule by selector(s)
13947     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13948     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13949     * @return {CSSRule} The CSS rule or null if one is not found
13950     */
13951    getRule : function(selector, refreshCache){
13952                 var rs = this.getRules(refreshCache);
13953                 if(!(selector instanceof Array)){
13954                     return rs[selector];
13955                 }
13956                 for(var i = 0; i < selector.length; i++){
13957                         if(rs[selector[i]]){
13958                                 return rs[selector[i]];
13959                         }
13960                 }
13961                 return null;
13962         },
13963         
13964         
13965         /**
13966     * Updates a rule property
13967     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13968     * @param {String} property The css property
13969     * @param {String} value The new value for the property
13970     * @return {Boolean} true If a rule was found and updated
13971     */
13972    updateRule : function(selector, property, value){
13973                 if(!(selector instanceof Array)){
13974                         var rule = this.getRule(selector);
13975                         if(rule){
13976                                 rule.style[property.replace(camelRe, camelFn)] = value;
13977                                 return true;
13978                         }
13979                 }else{
13980                         for(var i = 0; i < selector.length; i++){
13981                                 if(this.updateRule(selector[i], property, value)){
13982                                         return true;
13983                                 }
13984                         }
13985                 }
13986                 return false;
13987         }
13988    };   
13989 }();/*
13990  * Based on:
13991  * Ext JS Library 1.1.1
13992  * Copyright(c) 2006-2007, Ext JS, LLC.
13993  *
13994  * Originally Released Under LGPL - original licence link has changed is not relivant.
13995  *
13996  * Fork - LGPL
13997  * <script type="text/javascript">
13998  */
13999
14000  
14001
14002 /**
14003  * @class Roo.util.ClickRepeater
14004  * @extends Roo.util.Observable
14005  * 
14006  * A wrapper class which can be applied to any element. Fires a "click" event while the
14007  * mouse is pressed. The interval between firings may be specified in the config but
14008  * defaults to 10 milliseconds.
14009  * 
14010  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14011  * 
14012  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14013  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14014  * Similar to an autorepeat key delay.
14015  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14016  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14017  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14018  *           "interval" and "delay" are ignored. "immediate" is honored.
14019  * @cfg {Boolean} preventDefault True to prevent the default click event
14020  * @cfg {Boolean} stopDefault True to stop the default click event
14021  * 
14022  * @history
14023  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14024  *     2007-02-02 jvs Renamed to ClickRepeater
14025  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14026  *
14027  *  @constructor
14028  * @param {String/HTMLElement/Element} el The element to listen on
14029  * @param {Object} config
14030  **/
14031 Roo.util.ClickRepeater = function(el, config)
14032 {
14033     this.el = Roo.get(el);
14034     this.el.unselectable();
14035
14036     Roo.apply(this, config);
14037
14038     this.addEvents({
14039     /**
14040      * @event mousedown
14041      * Fires when the mouse button is depressed.
14042      * @param {Roo.util.ClickRepeater} this
14043      */
14044         "mousedown" : true,
14045     /**
14046      * @event click
14047      * Fires on a specified interval during the time the element is pressed.
14048      * @param {Roo.util.ClickRepeater} this
14049      */
14050         "click" : true,
14051     /**
14052      * @event mouseup
14053      * Fires when the mouse key is released.
14054      * @param {Roo.util.ClickRepeater} this
14055      */
14056         "mouseup" : true
14057     });
14058
14059     this.el.on("mousedown", this.handleMouseDown, this);
14060     if(this.preventDefault || this.stopDefault){
14061         this.el.on("click", function(e){
14062             if(this.preventDefault){
14063                 e.preventDefault();
14064             }
14065             if(this.stopDefault){
14066                 e.stopEvent();
14067             }
14068         }, this);
14069     }
14070
14071     // allow inline handler
14072     if(this.handler){
14073         this.on("click", this.handler,  this.scope || this);
14074     }
14075
14076     Roo.util.ClickRepeater.superclass.constructor.call(this);
14077 };
14078
14079 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14080     interval : 20,
14081     delay: 250,
14082     preventDefault : true,
14083     stopDefault : false,
14084     timer : 0,
14085
14086     // private
14087     handleMouseDown : function(){
14088         clearTimeout(this.timer);
14089         this.el.blur();
14090         if(this.pressClass){
14091             this.el.addClass(this.pressClass);
14092         }
14093         this.mousedownTime = new Date();
14094
14095         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14096         this.el.on("mouseout", this.handleMouseOut, this);
14097
14098         this.fireEvent("mousedown", this);
14099         this.fireEvent("click", this);
14100         
14101         this.timer = this.click.defer(this.delay || this.interval, this);
14102     },
14103
14104     // private
14105     click : function(){
14106         this.fireEvent("click", this);
14107         this.timer = this.click.defer(this.getInterval(), this);
14108     },
14109
14110     // private
14111     getInterval: function(){
14112         if(!this.accelerate){
14113             return this.interval;
14114         }
14115         var pressTime = this.mousedownTime.getElapsed();
14116         if(pressTime < 500){
14117             return 400;
14118         }else if(pressTime < 1700){
14119             return 320;
14120         }else if(pressTime < 2600){
14121             return 250;
14122         }else if(pressTime < 3500){
14123             return 180;
14124         }else if(pressTime < 4400){
14125             return 140;
14126         }else if(pressTime < 5300){
14127             return 80;
14128         }else if(pressTime < 6200){
14129             return 50;
14130         }else{
14131             return 10;
14132         }
14133     },
14134
14135     // private
14136     handleMouseOut : function(){
14137         clearTimeout(this.timer);
14138         if(this.pressClass){
14139             this.el.removeClass(this.pressClass);
14140         }
14141         this.el.on("mouseover", this.handleMouseReturn, this);
14142     },
14143
14144     // private
14145     handleMouseReturn : function(){
14146         this.el.un("mouseover", this.handleMouseReturn);
14147         if(this.pressClass){
14148             this.el.addClass(this.pressClass);
14149         }
14150         this.click();
14151     },
14152
14153     // private
14154     handleMouseUp : function(){
14155         clearTimeout(this.timer);
14156         this.el.un("mouseover", this.handleMouseReturn);
14157         this.el.un("mouseout", this.handleMouseOut);
14158         Roo.get(document).un("mouseup", this.handleMouseUp);
14159         this.el.removeClass(this.pressClass);
14160         this.fireEvent("mouseup", this);
14161     }
14162 });/*
14163  * Based on:
14164  * Ext JS Library 1.1.1
14165  * Copyright(c) 2006-2007, Ext JS, LLC.
14166  *
14167  * Originally Released Under LGPL - original licence link has changed is not relivant.
14168  *
14169  * Fork - LGPL
14170  * <script type="text/javascript">
14171  */
14172
14173  
14174 /**
14175  * @class Roo.KeyNav
14176  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14177  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14178  * way to implement custom navigation schemes for any UI component.</p>
14179  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14180  * pageUp, pageDown, del, home, end.  Usage:</p>
14181  <pre><code>
14182 var nav = new Roo.KeyNav("my-element", {
14183     "left" : function(e){
14184         this.moveLeft(e.ctrlKey);
14185     },
14186     "right" : function(e){
14187         this.moveRight(e.ctrlKey);
14188     },
14189     "enter" : function(e){
14190         this.save();
14191     },
14192     scope : this
14193 });
14194 </code></pre>
14195  * @constructor
14196  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14197  * @param {Object} config The config
14198  */
14199 Roo.KeyNav = function(el, config){
14200     this.el = Roo.get(el);
14201     Roo.apply(this, config);
14202     if(!this.disabled){
14203         this.disabled = true;
14204         this.enable();
14205     }
14206 };
14207
14208 Roo.KeyNav.prototype = {
14209     /**
14210      * @cfg {Boolean} disabled
14211      * True to disable this KeyNav instance (defaults to false)
14212      */
14213     disabled : false,
14214     /**
14215      * @cfg {String} defaultEventAction
14216      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14217      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14218      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14219      */
14220     defaultEventAction: "stopEvent",
14221     /**
14222      * @cfg {Boolean} forceKeyDown
14223      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14224      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14225      * handle keydown instead of keypress.
14226      */
14227     forceKeyDown : false,
14228
14229     // private
14230     prepareEvent : function(e){
14231         var k = e.getKey();
14232         var h = this.keyToHandler[k];
14233         //if(h && this[h]){
14234         //    e.stopPropagation();
14235         //}
14236         if(Roo.isSafari && h && k >= 37 && k <= 40){
14237             e.stopEvent();
14238         }
14239     },
14240
14241     // private
14242     relay : function(e){
14243         var k = e.getKey();
14244         var h = this.keyToHandler[k];
14245         if(h && this[h]){
14246             if(this.doRelay(e, this[h], h) !== true){
14247                 e[this.defaultEventAction]();
14248             }
14249         }
14250     },
14251
14252     // private
14253     doRelay : function(e, h, hname){
14254         return h.call(this.scope || this, e);
14255     },
14256
14257     // possible handlers
14258     enter : false,
14259     left : false,
14260     right : false,
14261     up : false,
14262     down : false,
14263     tab : false,
14264     esc : false,
14265     pageUp : false,
14266     pageDown : false,
14267     del : false,
14268     home : false,
14269     end : false,
14270
14271     // quick lookup hash
14272     keyToHandler : {
14273         37 : "left",
14274         39 : "right",
14275         38 : "up",
14276         40 : "down",
14277         33 : "pageUp",
14278         34 : "pageDown",
14279         46 : "del",
14280         36 : "home",
14281         35 : "end",
14282         13 : "enter",
14283         27 : "esc",
14284         9  : "tab"
14285     },
14286
14287         /**
14288          * Enable this KeyNav
14289          */
14290         enable: function(){
14291                 if(this.disabled){
14292             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14293             // the EventObject will normalize Safari automatically
14294             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14295                 this.el.on("keydown", this.relay,  this);
14296             }else{
14297                 this.el.on("keydown", this.prepareEvent,  this);
14298                 this.el.on("keypress", this.relay,  this);
14299             }
14300                     this.disabled = false;
14301                 }
14302         },
14303
14304         /**
14305          * Disable this KeyNav
14306          */
14307         disable: function(){
14308                 if(!this.disabled){
14309                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14310                 this.el.un("keydown", this.relay);
14311             }else{
14312                 this.el.un("keydown", this.prepareEvent);
14313                 this.el.un("keypress", this.relay);
14314             }
14315                     this.disabled = true;
14316                 }
14317         }
14318 };/*
14319  * Based on:
14320  * Ext JS Library 1.1.1
14321  * Copyright(c) 2006-2007, Ext JS, LLC.
14322  *
14323  * Originally Released Under LGPL - original licence link has changed is not relivant.
14324  *
14325  * Fork - LGPL
14326  * <script type="text/javascript">
14327  */
14328
14329  
14330 /**
14331  * @class Roo.KeyMap
14332  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14333  * The constructor accepts the same config object as defined by {@link #addBinding}.
14334  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14335  * combination it will call the function with this signature (if the match is a multi-key
14336  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14337  * A KeyMap can also handle a string representation of keys.<br />
14338  * Usage:
14339  <pre><code>
14340 // map one key by key code
14341 var map = new Roo.KeyMap("my-element", {
14342     key: 13, // or Roo.EventObject.ENTER
14343     fn: myHandler,
14344     scope: myObject
14345 });
14346
14347 // map multiple keys to one action by string
14348 var map = new Roo.KeyMap("my-element", {
14349     key: "a\r\n\t",
14350     fn: myHandler,
14351     scope: myObject
14352 });
14353
14354 // map multiple keys to multiple actions by strings and array of codes
14355 var map = new Roo.KeyMap("my-element", [
14356     {
14357         key: [10,13],
14358         fn: function(){ alert("Return was pressed"); }
14359     }, {
14360         key: "abc",
14361         fn: function(){ alert('a, b or c was pressed'); }
14362     }, {
14363         key: "\t",
14364         ctrl:true,
14365         shift:true,
14366         fn: function(){ alert('Control + shift + tab was pressed.'); }
14367     }
14368 ]);
14369 </code></pre>
14370  * <b>Note: A KeyMap starts enabled</b>
14371  * @constructor
14372  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14373  * @param {Object} config The config (see {@link #addBinding})
14374  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14375  */
14376 Roo.KeyMap = function(el, config, eventName){
14377     this.el  = Roo.get(el);
14378     this.eventName = eventName || "keydown";
14379     this.bindings = [];
14380     if(config){
14381         this.addBinding(config);
14382     }
14383     this.enable();
14384 };
14385
14386 Roo.KeyMap.prototype = {
14387     /**
14388      * True to stop the event from bubbling and prevent the default browser action if the
14389      * key was handled by the KeyMap (defaults to false)
14390      * @type Boolean
14391      */
14392     stopEvent : false,
14393
14394     /**
14395      * Add a new binding to this KeyMap. The following config object properties are supported:
14396      * <pre>
14397 Property    Type             Description
14398 ----------  ---------------  ----------------------------------------------------------------------
14399 key         String/Array     A single keycode or an array of keycodes to handle
14400 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14401 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14402 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14403 fn          Function         The function to call when KeyMap finds the expected key combination
14404 scope       Object           The scope of the callback function
14405 </pre>
14406      *
14407      * Usage:
14408      * <pre><code>
14409 // Create a KeyMap
14410 var map = new Roo.KeyMap(document, {
14411     key: Roo.EventObject.ENTER,
14412     fn: handleKey,
14413     scope: this
14414 });
14415
14416 //Add a new binding to the existing KeyMap later
14417 map.addBinding({
14418     key: 'abc',
14419     shift: true,
14420     fn: handleKey,
14421     scope: this
14422 });
14423 </code></pre>
14424      * @param {Object/Array} config A single KeyMap config or an array of configs
14425      */
14426         addBinding : function(config){
14427         if(config instanceof Array){
14428             for(var i = 0, len = config.length; i < len; i++){
14429                 this.addBinding(config[i]);
14430             }
14431             return;
14432         }
14433         var keyCode = config.key,
14434             shift = config.shift, 
14435             ctrl = config.ctrl, 
14436             alt = config.alt,
14437             fn = config.fn,
14438             scope = config.scope;
14439         if(typeof keyCode == "string"){
14440             var ks = [];
14441             var keyString = keyCode.toUpperCase();
14442             for(var j = 0, len = keyString.length; j < len; j++){
14443                 ks.push(keyString.charCodeAt(j));
14444             }
14445             keyCode = ks;
14446         }
14447         var keyArray = keyCode instanceof Array;
14448         var handler = function(e){
14449             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14450                 var k = e.getKey();
14451                 if(keyArray){
14452                     for(var i = 0, len = keyCode.length; i < len; i++){
14453                         if(keyCode[i] == k){
14454                           if(this.stopEvent){
14455                               e.stopEvent();
14456                           }
14457                           fn.call(scope || window, k, e);
14458                           return;
14459                         }
14460                     }
14461                 }else{
14462                     if(k == keyCode){
14463                         if(this.stopEvent){
14464                            e.stopEvent();
14465                         }
14466                         fn.call(scope || window, k, e);
14467                     }
14468                 }
14469             }
14470         };
14471         this.bindings.push(handler);  
14472         },
14473
14474     /**
14475      * Shorthand for adding a single key listener
14476      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14477      * following options:
14478      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14479      * @param {Function} fn The function to call
14480      * @param {Object} scope (optional) The scope of the function
14481      */
14482     on : function(key, fn, scope){
14483         var keyCode, shift, ctrl, alt;
14484         if(typeof key == "object" && !(key instanceof Array)){
14485             keyCode = key.key;
14486             shift = key.shift;
14487             ctrl = key.ctrl;
14488             alt = key.alt;
14489         }else{
14490             keyCode = key;
14491         }
14492         this.addBinding({
14493             key: keyCode,
14494             shift: shift,
14495             ctrl: ctrl,
14496             alt: alt,
14497             fn: fn,
14498             scope: scope
14499         })
14500     },
14501
14502     // private
14503     handleKeyDown : function(e){
14504             if(this.enabled){ //just in case
14505             var b = this.bindings;
14506             for(var i = 0, len = b.length; i < len; i++){
14507                 b[i].call(this, e);
14508             }
14509             }
14510         },
14511         
14512         /**
14513          * Returns true if this KeyMap is enabled
14514          * @return {Boolean} 
14515          */
14516         isEnabled : function(){
14517             return this.enabled;  
14518         },
14519         
14520         /**
14521          * Enables this KeyMap
14522          */
14523         enable: function(){
14524                 if(!this.enabled){
14525                     this.el.on(this.eventName, this.handleKeyDown, this);
14526                     this.enabled = true;
14527                 }
14528         },
14529
14530         /**
14531          * Disable this KeyMap
14532          */
14533         disable: function(){
14534                 if(this.enabled){
14535                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14536                     this.enabled = false;
14537                 }
14538         }
14539 };/*
14540  * Based on:
14541  * Ext JS Library 1.1.1
14542  * Copyright(c) 2006-2007, Ext JS, LLC.
14543  *
14544  * Originally Released Under LGPL - original licence link has changed is not relivant.
14545  *
14546  * Fork - LGPL
14547  * <script type="text/javascript">
14548  */
14549
14550  
14551 /**
14552  * @class Roo.util.TextMetrics
14553  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14554  * wide, in pixels, a given block of text will be.
14555  * @singleton
14556  */
14557 Roo.util.TextMetrics = function(){
14558     var shared;
14559     return {
14560         /**
14561          * Measures the size of the specified text
14562          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14563          * that can affect the size of the rendered text
14564          * @param {String} text The text to measure
14565          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14566          * in order to accurately measure the text height
14567          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14568          */
14569         measure : function(el, text, fixedWidth){
14570             if(!shared){
14571                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14572             }
14573             shared.bind(el);
14574             shared.setFixedWidth(fixedWidth || 'auto');
14575             return shared.getSize(text);
14576         },
14577
14578         /**
14579          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14580          * the overhead of multiple calls to initialize the style properties on each measurement.
14581          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14582          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14583          * in order to accurately measure the text height
14584          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14585          */
14586         createInstance : function(el, fixedWidth){
14587             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14588         }
14589     };
14590 }();
14591
14592  
14593
14594 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14595     var ml = new Roo.Element(document.createElement('div'));
14596     document.body.appendChild(ml.dom);
14597     ml.position('absolute');
14598     ml.setLeftTop(-1000, -1000);
14599     ml.hide();
14600
14601     if(fixedWidth){
14602         ml.setWidth(fixedWidth);
14603     }
14604      
14605     var instance = {
14606         /**
14607          * Returns the size of the specified text based on the internal element's style and width properties
14608          * @memberOf Roo.util.TextMetrics.Instance#
14609          * @param {String} text The text to measure
14610          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14611          */
14612         getSize : function(text){
14613             ml.update(text);
14614             var s = ml.getSize();
14615             ml.update('');
14616             return s;
14617         },
14618
14619         /**
14620          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14621          * that can affect the size of the rendered text
14622          * @memberOf Roo.util.TextMetrics.Instance#
14623          * @param {String/HTMLElement} el The element, dom node or id
14624          */
14625         bind : function(el){
14626             ml.setStyle(
14627                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14628             );
14629         },
14630
14631         /**
14632          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14633          * to set a fixed width in order to accurately measure the text height.
14634          * @memberOf Roo.util.TextMetrics.Instance#
14635          * @param {Number} width The width to set on the element
14636          */
14637         setFixedWidth : function(width){
14638             ml.setWidth(width);
14639         },
14640
14641         /**
14642          * Returns the measured width of the specified text
14643          * @memberOf Roo.util.TextMetrics.Instance#
14644          * @param {String} text The text to measure
14645          * @return {Number} width The width in pixels
14646          */
14647         getWidth : function(text){
14648             ml.dom.style.width = 'auto';
14649             return this.getSize(text).width;
14650         },
14651
14652         /**
14653          * Returns the measured height of the specified text.  For multiline text, be sure to call
14654          * {@link #setFixedWidth} if necessary.
14655          * @memberOf Roo.util.TextMetrics.Instance#
14656          * @param {String} text The text to measure
14657          * @return {Number} height The height in pixels
14658          */
14659         getHeight : function(text){
14660             return this.getSize(text).height;
14661         }
14662     };
14663
14664     instance.bind(bindTo);
14665
14666     return instance;
14667 };
14668
14669 // backwards compat
14670 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14671  * Based on:
14672  * Ext JS Library 1.1.1
14673  * Copyright(c) 2006-2007, Ext JS, LLC.
14674  *
14675  * Originally Released Under LGPL - original licence link has changed is not relivant.
14676  *
14677  * Fork - LGPL
14678  * <script type="text/javascript">
14679  */
14680
14681 /**
14682  * @class Roo.state.Provider
14683  * Abstract base class for state provider implementations. This class provides methods
14684  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14685  * Provider interface.
14686  */
14687 Roo.state.Provider = function(){
14688     /**
14689      * @event statechange
14690      * Fires when a state change occurs.
14691      * @param {Provider} this This state provider
14692      * @param {String} key The state key which was changed
14693      * @param {String} value The encoded value for the state
14694      */
14695     this.addEvents({
14696         "statechange": true
14697     });
14698     this.state = {};
14699     Roo.state.Provider.superclass.constructor.call(this);
14700 };
14701 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14702     /**
14703      * Returns the current value for a key
14704      * @param {String} name The key name
14705      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14706      * @return {Mixed} The state data
14707      */
14708     get : function(name, defaultValue){
14709         return typeof this.state[name] == "undefined" ?
14710             defaultValue : this.state[name];
14711     },
14712     
14713     /**
14714      * Clears a value from the state
14715      * @param {String} name The key name
14716      */
14717     clear : function(name){
14718         delete this.state[name];
14719         this.fireEvent("statechange", this, name, null);
14720     },
14721     
14722     /**
14723      * Sets the value for a key
14724      * @param {String} name The key name
14725      * @param {Mixed} value The value to set
14726      */
14727     set : function(name, value){
14728         this.state[name] = value;
14729         this.fireEvent("statechange", this, name, value);
14730     },
14731     
14732     /**
14733      * Decodes a string previously encoded with {@link #encodeValue}.
14734      * @param {String} value The value to decode
14735      * @return {Mixed} The decoded value
14736      */
14737     decodeValue : function(cookie){
14738         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14739         var matches = re.exec(unescape(cookie));
14740         if(!matches || !matches[1]) return; // non state cookie
14741         var type = matches[1];
14742         var v = matches[2];
14743         switch(type){
14744             case "n":
14745                 return parseFloat(v);
14746             case "d":
14747                 return new Date(Date.parse(v));
14748             case "b":
14749                 return (v == "1");
14750             case "a":
14751                 var all = [];
14752                 var values = v.split("^");
14753                 for(var i = 0, len = values.length; i < len; i++){
14754                     all.push(this.decodeValue(values[i]));
14755                 }
14756                 return all;
14757            case "o":
14758                 var all = {};
14759                 var values = v.split("^");
14760                 for(var i = 0, len = values.length; i < len; i++){
14761                     var kv = values[i].split("=");
14762                     all[kv[0]] = this.decodeValue(kv[1]);
14763                 }
14764                 return all;
14765            default:
14766                 return v;
14767         }
14768     },
14769     
14770     /**
14771      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14772      * @param {Mixed} value The value to encode
14773      * @return {String} The encoded value
14774      */
14775     encodeValue : function(v){
14776         var enc;
14777         if(typeof v == "number"){
14778             enc = "n:" + v;
14779         }else if(typeof v == "boolean"){
14780             enc = "b:" + (v ? "1" : "0");
14781         }else if(v instanceof Date){
14782             enc = "d:" + v.toGMTString();
14783         }else if(v instanceof Array){
14784             var flat = "";
14785             for(var i = 0, len = v.length; i < len; i++){
14786                 flat += this.encodeValue(v[i]);
14787                 if(i != len-1) flat += "^";
14788             }
14789             enc = "a:" + flat;
14790         }else if(typeof v == "object"){
14791             var flat = "";
14792             for(var key in v){
14793                 if(typeof v[key] != "function"){
14794                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14795                 }
14796             }
14797             enc = "o:" + flat.substring(0, flat.length-1);
14798         }else{
14799             enc = "s:" + v;
14800         }
14801         return escape(enc);        
14802     }
14803 });
14804
14805 /*
14806  * Based on:
14807  * Ext JS Library 1.1.1
14808  * Copyright(c) 2006-2007, Ext JS, LLC.
14809  *
14810  * Originally Released Under LGPL - original licence link has changed is not relivant.
14811  *
14812  * Fork - LGPL
14813  * <script type="text/javascript">
14814  */
14815 /**
14816  * @class Roo.state.Manager
14817  * This is the global state manager. By default all components that are "state aware" check this class
14818  * for state information if you don't pass them a custom state provider. In order for this class
14819  * to be useful, it must be initialized with a provider when your application initializes.
14820  <pre><code>
14821 // in your initialization function
14822 init : function(){
14823    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14824    ...
14825    // supposed you have a {@link Roo.BorderLayout}
14826    var layout = new Roo.BorderLayout(...);
14827    layout.restoreState();
14828    // or a {Roo.BasicDialog}
14829    var dialog = new Roo.BasicDialog(...);
14830    dialog.restoreState();
14831  </code></pre>
14832  * @singleton
14833  */
14834 Roo.state.Manager = function(){
14835     var provider = new Roo.state.Provider();
14836     
14837     return {
14838         /**
14839          * Configures the default state provider for your application
14840          * @param {Provider} stateProvider The state provider to set
14841          */
14842         setProvider : function(stateProvider){
14843             provider = stateProvider;
14844         },
14845         
14846         /**
14847          * Returns the current value for a key
14848          * @param {String} name The key name
14849          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14850          * @return {Mixed} The state data
14851          */
14852         get : function(key, defaultValue){
14853             return provider.get(key, defaultValue);
14854         },
14855         
14856         /**
14857          * Sets the value for a key
14858          * @param {String} name The key name
14859          * @param {Mixed} value The state data
14860          */
14861          set : function(key, value){
14862             provider.set(key, value);
14863         },
14864         
14865         /**
14866          * Clears a value from the state
14867          * @param {String} name The key name
14868          */
14869         clear : function(key){
14870             provider.clear(key);
14871         },
14872         
14873         /**
14874          * Gets the currently configured state provider
14875          * @return {Provider} The state provider
14876          */
14877         getProvider : function(){
14878             return provider;
14879         }
14880     };
14881 }();
14882 /*
14883  * Based on:
14884  * Ext JS Library 1.1.1
14885  * Copyright(c) 2006-2007, Ext JS, LLC.
14886  *
14887  * Originally Released Under LGPL - original licence link has changed is not relivant.
14888  *
14889  * Fork - LGPL
14890  * <script type="text/javascript">
14891  */
14892 /**
14893  * @class Roo.state.CookieProvider
14894  * @extends Roo.state.Provider
14895  * The default Provider implementation which saves state via cookies.
14896  * <br />Usage:
14897  <pre><code>
14898    var cp = new Roo.state.CookieProvider({
14899        path: "/cgi-bin/",
14900        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14901        domain: "roojs.com"
14902    })
14903    Roo.state.Manager.setProvider(cp);
14904  </code></pre>
14905  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14906  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14907  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14908  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14909  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14910  * domain the page is running on including the 'www' like 'www.roojs.com')
14911  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14912  * @constructor
14913  * Create a new CookieProvider
14914  * @param {Object} config The configuration object
14915  */
14916 Roo.state.CookieProvider = function(config){
14917     Roo.state.CookieProvider.superclass.constructor.call(this);
14918     this.path = "/";
14919     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14920     this.domain = null;
14921     this.secure = false;
14922     Roo.apply(this, config);
14923     this.state = this.readCookies();
14924 };
14925
14926 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14927     // private
14928     set : function(name, value){
14929         if(typeof value == "undefined" || value === null){
14930             this.clear(name);
14931             return;
14932         }
14933         this.setCookie(name, value);
14934         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14935     },
14936
14937     // private
14938     clear : function(name){
14939         this.clearCookie(name);
14940         Roo.state.CookieProvider.superclass.clear.call(this, name);
14941     },
14942
14943     // private
14944     readCookies : function(){
14945         var cookies = {};
14946         var c = document.cookie + ";";
14947         var re = /\s?(.*?)=(.*?);/g;
14948         var matches;
14949         while((matches = re.exec(c)) != null){
14950             var name = matches[1];
14951             var value = matches[2];
14952             if(name && name.substring(0,3) == "ys-"){
14953                 cookies[name.substr(3)] = this.decodeValue(value);
14954             }
14955         }
14956         return cookies;
14957     },
14958
14959     // private
14960     setCookie : function(name, value){
14961         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14962            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14963            ((this.path == null) ? "" : ("; path=" + this.path)) +
14964            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14965            ((this.secure == true) ? "; secure" : "");
14966     },
14967
14968     // private
14969     clearCookie : function(name){
14970         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14971            ((this.path == null) ? "" : ("; path=" + this.path)) +
14972            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14973            ((this.secure == true) ? "; secure" : "");
14974     }
14975 });/*
14976  * Based on:
14977  * Ext JS Library 1.1.1
14978  * Copyright(c) 2006-2007, Ext JS, LLC.
14979  *
14980  * Originally Released Under LGPL - original licence link has changed is not relivant.
14981  *
14982  * Fork - LGPL
14983  * <script type="text/javascript">
14984  */
14985  
14986
14987 /**
14988  * @class Roo.ComponentMgr
14989  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14990  * @singleton
14991  */
14992 Roo.ComponentMgr = function(){
14993     var all = new Roo.util.MixedCollection();
14994
14995     return {
14996         /**
14997          * Registers a component.
14998          * @param {Roo.Component} c The component
14999          */
15000         register : function(c){
15001             all.add(c);
15002         },
15003
15004         /**
15005          * Unregisters a component.
15006          * @param {Roo.Component} c The component
15007          */
15008         unregister : function(c){
15009             all.remove(c);
15010         },
15011
15012         /**
15013          * Returns a component by id
15014          * @param {String} id The component id
15015          */
15016         get : function(id){
15017             return all.get(id);
15018         },
15019
15020         /**
15021          * Registers a function that will be called when a specified component is added to ComponentMgr
15022          * @param {String} id The component id
15023          * @param {Funtction} fn The callback function
15024          * @param {Object} scope The scope of the callback
15025          */
15026         onAvailable : function(id, fn, scope){
15027             all.on("add", function(index, o){
15028                 if(o.id == id){
15029                     fn.call(scope || o, o);
15030                     all.un("add", fn, scope);
15031                 }
15032             });
15033         }
15034     };
15035 }();/*
15036  * Based on:
15037  * Ext JS Library 1.1.1
15038  * Copyright(c) 2006-2007, Ext JS, LLC.
15039  *
15040  * Originally Released Under LGPL - original licence link has changed is not relivant.
15041  *
15042  * Fork - LGPL
15043  * <script type="text/javascript">
15044  */
15045  
15046 /**
15047  * @class Roo.Component
15048  * @extends Roo.util.Observable
15049  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15050  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15051  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15052  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15053  * All visual components (widgets) that require rendering into a layout should subclass Component.
15054  * @constructor
15055  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15056  * element and its id used as the component id.  If a string is passed, it is assumed to be the id of an existing element
15057  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15058  */
15059 Roo.Component = function(config){
15060     config = config || {};
15061     if(config.tagName || config.dom || typeof config == "string"){ // element object
15062         config = {el: config, id: config.id || config};
15063     }
15064     this.initialConfig = config;
15065
15066     Roo.apply(this, config);
15067     this.addEvents({
15068         /**
15069          * @event disable
15070          * Fires after the component is disabled.
15071              * @param {Roo.Component} this
15072              */
15073         disable : true,
15074         /**
15075          * @event enable
15076          * Fires after the component is enabled.
15077              * @param {Roo.Component} this
15078              */
15079         enable : true,
15080         /**
15081          * @event beforeshow
15082          * Fires before the component is shown.  Return false to stop the show.
15083              * @param {Roo.Component} this
15084              */
15085         beforeshow : true,
15086         /**
15087          * @event show
15088          * Fires after the component is shown.
15089              * @param {Roo.Component} this
15090              */
15091         show : true,
15092         /**
15093          * @event beforehide
15094          * Fires before the component is hidden. Return false to stop the hide.
15095              * @param {Roo.Component} this
15096              */
15097         beforehide : true,
15098         /**
15099          * @event hide
15100          * Fires after the component is hidden.
15101              * @param {Roo.Component} this
15102              */
15103         hide : true,
15104         /**
15105          * @event beforerender
15106          * Fires before the component is rendered. Return false to stop the render.
15107              * @param {Roo.Component} this
15108              */
15109         beforerender : true,
15110         /**
15111          * @event render
15112          * Fires after the component is rendered.
15113              * @param {Roo.Component} this
15114              */
15115         render : true,
15116         /**
15117          * @event beforedestroy
15118          * Fires before the component is destroyed. Return false to stop the destroy.
15119              * @param {Roo.Component} this
15120              */
15121         beforedestroy : true,
15122         /**
15123          * @event destroy
15124          * Fires after the component is destroyed.
15125              * @param {Roo.Component} this
15126              */
15127         destroy : true
15128     });
15129     if(!this.id){
15130         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15131     }
15132     Roo.ComponentMgr.register(this);
15133     Roo.Component.superclass.constructor.call(this);
15134     this.initComponent();
15135     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15136         this.render(this.renderTo);
15137         delete this.renderTo;
15138     }
15139 };
15140
15141 /** @private */
15142 Roo.Component.AUTO_ID = 1000;
15143
15144 Roo.extend(Roo.Component, Roo.util.Observable, {
15145     /**
15146      * @scope Roo.Component.prototype
15147      * @type {Boolean}
15148      * true if this component is hidden. Read-only.
15149      */
15150     hidden : false,
15151     /**
15152      * @type {Boolean}
15153      * true if this component is disabled. Read-only.
15154      */
15155     disabled : false,
15156     /**
15157      * @type {Boolean}
15158      * true if this component has been rendered. Read-only.
15159      */
15160     rendered : false,
15161     
15162     /** @cfg {String} disableClass
15163      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15164      */
15165     disabledClass : "x-item-disabled",
15166         /** @cfg {Boolean} allowDomMove
15167          * Whether the component can move the Dom node when rendering (defaults to true).
15168          */
15169     allowDomMove : true,
15170     /** @cfg {String} hideMode
15171      * How this component should hidden. Supported values are
15172      * "visibility" (css visibility), "offsets" (negative offset position) and
15173      * "display" (css display) - defaults to "display".
15174      */
15175     hideMode: 'display',
15176
15177     /** @private */
15178     ctype : "Roo.Component",
15179
15180     /**
15181      * @cfg {String} actionMode 
15182      * which property holds the element that used for  hide() / show() / disable() / enable()
15183      * default is 'el' 
15184      */
15185     actionMode : "el",
15186
15187     /** @private */
15188     getActionEl : function(){
15189         return this[this.actionMode];
15190     },
15191
15192     initComponent : Roo.emptyFn,
15193     /**
15194      * If this is a lazy rendering component, render it to its container element.
15195      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15196      */
15197     render : function(container, position){
15198         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15199             if(!container && this.el){
15200                 this.el = Roo.get(this.el);
15201                 container = this.el.dom.parentNode;
15202                 this.allowDomMove = false;
15203             }
15204             this.container = Roo.get(container);
15205             this.rendered = true;
15206             if(position !== undefined){
15207                 if(typeof position == 'number'){
15208                     position = this.container.dom.childNodes[position];
15209                 }else{
15210                     position = Roo.getDom(position);
15211                 }
15212             }
15213             this.onRender(this.container, position || null);
15214             if(this.cls){
15215                 this.el.addClass(this.cls);
15216                 delete this.cls;
15217             }
15218             if(this.style){
15219                 this.el.applyStyles(this.style);
15220                 delete this.style;
15221             }
15222             this.fireEvent("render", this);
15223             this.afterRender(this.container);
15224             if(this.hidden){
15225                 this.hide();
15226             }
15227             if(this.disabled){
15228                 this.disable();
15229             }
15230         }
15231         return this;
15232     },
15233
15234     /** @private */
15235     // default function is not really useful
15236     onRender : function(ct, position){
15237         if(this.el){
15238             this.el = Roo.get(this.el);
15239             if(this.allowDomMove !== false){
15240                 ct.dom.insertBefore(this.el.dom, position);
15241             }
15242         }
15243     },
15244
15245     /** @private */
15246     getAutoCreate : function(){
15247         var cfg = typeof this.autoCreate == "object" ?
15248                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15249         if(this.id && !cfg.id){
15250             cfg.id = this.id;
15251         }
15252         return cfg;
15253     },
15254
15255     /** @private */
15256     afterRender : Roo.emptyFn,
15257
15258     /**
15259      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15260      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15261      */
15262     destroy : function(){
15263         if(this.fireEvent("beforedestroy", this) !== false){
15264             this.purgeListeners();
15265             this.beforeDestroy();
15266             if(this.rendered){
15267                 this.el.removeAllListeners();
15268                 this.el.remove();
15269                 if(this.actionMode == "container"){
15270                     this.container.remove();
15271                 }
15272             }
15273             this.onDestroy();
15274             Roo.ComponentMgr.unregister(this);
15275             this.fireEvent("destroy", this);
15276         }
15277     },
15278
15279         /** @private */
15280     beforeDestroy : function(){
15281
15282     },
15283
15284         /** @private */
15285         onDestroy : function(){
15286
15287     },
15288
15289     /**
15290      * Returns the underlying {@link Roo.Element}.
15291      * @return {Roo.Element} The element
15292      */
15293     getEl : function(){
15294         return this.el;
15295     },
15296
15297     /**
15298      * Returns the id of this component.
15299      * @return {String}
15300      */
15301     getId : function(){
15302         return this.id;
15303     },
15304
15305     /**
15306      * Try to focus this component.
15307      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15308      * @return {Roo.Component} this
15309      */
15310     focus : function(selectText){
15311         if(this.rendered){
15312             this.el.focus();
15313             if(selectText === true){
15314                 this.el.dom.select();
15315             }
15316         }
15317         return this;
15318     },
15319
15320     /** @private */
15321     blur : function(){
15322         if(this.rendered){
15323             this.el.blur();
15324         }
15325         return this;
15326     },
15327
15328     /**
15329      * Disable this component.
15330      * @return {Roo.Component} this
15331      */
15332     disable : function(){
15333         if(this.rendered){
15334             this.onDisable();
15335         }
15336         this.disabled = true;
15337         this.fireEvent("disable", this);
15338         return this;
15339     },
15340
15341         // private
15342     onDisable : function(){
15343         this.getActionEl().addClass(this.disabledClass);
15344         this.el.dom.disabled = true;
15345     },
15346
15347     /**
15348      * Enable this component.
15349      * @return {Roo.Component} this
15350      */
15351     enable : function(){
15352         if(this.rendered){
15353             this.onEnable();
15354         }
15355         this.disabled = false;
15356         this.fireEvent("enable", this);
15357         return this;
15358     },
15359
15360         // private
15361     onEnable : function(){
15362         this.getActionEl().removeClass(this.disabledClass);
15363         this.el.dom.disabled = false;
15364     },
15365
15366     /**
15367      * Convenience function for setting disabled/enabled by boolean.
15368      * @param {Boolean} disabled
15369      */
15370     setDisabled : function(disabled){
15371         this[disabled ? "disable" : "enable"]();
15372     },
15373
15374     /**
15375      * Show this component.
15376      * @return {Roo.Component} this
15377      */
15378     show: function(){
15379         if(this.fireEvent("beforeshow", this) !== false){
15380             this.hidden = false;
15381             if(this.rendered){
15382                 this.onShow();
15383             }
15384             this.fireEvent("show", this);
15385         }
15386         return this;
15387     },
15388
15389     // private
15390     onShow : function(){
15391         var ae = this.getActionEl();
15392         if(this.hideMode == 'visibility'){
15393             ae.dom.style.visibility = "visible";
15394         }else if(this.hideMode == 'offsets'){
15395             ae.removeClass('x-hidden');
15396         }else{
15397             ae.dom.style.display = "";
15398         }
15399     },
15400
15401     /**
15402      * Hide this component.
15403      * @return {Roo.Component} this
15404      */
15405     hide: function(){
15406         if(this.fireEvent("beforehide", this) !== false){
15407             this.hidden = true;
15408             if(this.rendered){
15409                 this.onHide();
15410             }
15411             this.fireEvent("hide", this);
15412         }
15413         return this;
15414     },
15415
15416     // private
15417     onHide : function(){
15418         var ae = this.getActionEl();
15419         if(this.hideMode == 'visibility'){
15420             ae.dom.style.visibility = "hidden";
15421         }else if(this.hideMode == 'offsets'){
15422             ae.addClass('x-hidden');
15423         }else{
15424             ae.dom.style.display = "none";
15425         }
15426     },
15427
15428     /**
15429      * Convenience function to hide or show this component by boolean.
15430      * @param {Boolean} visible True to show, false to hide
15431      * @return {Roo.Component} this
15432      */
15433     setVisible: function(visible){
15434         if(visible) {
15435             this.show();
15436         }else{
15437             this.hide();
15438         }
15439         return this;
15440     },
15441
15442     /**
15443      * Returns true if this component is visible.
15444      */
15445     isVisible : function(){
15446         return this.getActionEl().isVisible();
15447     },
15448
15449     cloneConfig : function(overrides){
15450         overrides = overrides || {};
15451         var id = overrides.id || Roo.id();
15452         var cfg = Roo.applyIf(overrides, this.initialConfig);
15453         cfg.id = id; // prevent dup id
15454         return new this.constructor(cfg);
15455     }
15456 });/*
15457  * Based on:
15458  * Ext JS Library 1.1.1
15459  * Copyright(c) 2006-2007, Ext JS, LLC.
15460  *
15461  * Originally Released Under LGPL - original licence link has changed is not relivant.
15462  *
15463  * Fork - LGPL
15464  * <script type="text/javascript">
15465  */
15466
15467 /**
15468  * @class Roo.BoxComponent
15469  * @extends Roo.Component
15470  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15471  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15472  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15473  * layout containers.
15474  * @constructor
15475  * @param {Roo.Element/String/Object} config The configuration options.
15476  */
15477 Roo.BoxComponent = function(config){
15478     Roo.Component.call(this, config);
15479     this.addEvents({
15480         /**
15481          * @event resize
15482          * Fires after the component is resized.
15483              * @param {Roo.Component} this
15484              * @param {Number} adjWidth The box-adjusted width that was set
15485              * @param {Number} adjHeight The box-adjusted height that was set
15486              * @param {Number} rawWidth The width that was originally specified
15487              * @param {Number} rawHeight The height that was originally specified
15488              */
15489         resize : true,
15490         /**
15491          * @event move
15492          * Fires after the component is moved.
15493              * @param {Roo.Component} this
15494              * @param {Number} x The new x position
15495              * @param {Number} y The new y position
15496              */
15497         move : true
15498     });
15499 };
15500
15501 Roo.extend(Roo.BoxComponent, Roo.Component, {
15502     // private, set in afterRender to signify that the component has been rendered
15503     boxReady : false,
15504     // private, used to defer height settings to subclasses
15505     deferHeight: false,
15506     /** @cfg {Number} width
15507      * width (optional) size of component
15508      */
15509      /** @cfg {Number} height
15510      * height (optional) size of component
15511      */
15512      
15513     /**
15514      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15515      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15516      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15517      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15518      * @return {Roo.BoxComponent} this
15519      */
15520     setSize : function(w, h){
15521         // support for standard size objects
15522         if(typeof w == 'object'){
15523             h = w.height;
15524             w = w.width;
15525         }
15526         // not rendered
15527         if(!this.boxReady){
15528             this.width = w;
15529             this.height = h;
15530             return this;
15531         }
15532
15533         // prevent recalcs when not needed
15534         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15535             return this;
15536         }
15537         this.lastSize = {width: w, height: h};
15538
15539         var adj = this.adjustSize(w, h);
15540         var aw = adj.width, ah = adj.height;
15541         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15542             var rz = this.getResizeEl();
15543             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15544                 rz.setSize(aw, ah);
15545             }else if(!this.deferHeight && ah !== undefined){
15546                 rz.setHeight(ah);
15547             }else if(aw !== undefined){
15548                 rz.setWidth(aw);
15549             }
15550             this.onResize(aw, ah, w, h);
15551             this.fireEvent('resize', this, aw, ah, w, h);
15552         }
15553         return this;
15554     },
15555
15556     /**
15557      * Gets the current size of the component's underlying element.
15558      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15559      */
15560     getSize : function(){
15561         return this.el.getSize();
15562     },
15563
15564     /**
15565      * Gets the current XY position of the component's underlying element.
15566      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15567      * @return {Array} The XY position of the element (e.g., [100, 200])
15568      */
15569     getPosition : function(local){
15570         if(local === true){
15571             return [this.el.getLeft(true), this.el.getTop(true)];
15572         }
15573         return this.xy || this.el.getXY();
15574     },
15575
15576     /**
15577      * Gets the current box measurements of the component's underlying element.
15578      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15579      * @returns {Object} box An object in the format {x, y, width, height}
15580      */
15581     getBox : function(local){
15582         var s = this.el.getSize();
15583         if(local){
15584             s.x = this.el.getLeft(true);
15585             s.y = this.el.getTop(true);
15586         }else{
15587             var xy = this.xy || this.el.getXY();
15588             s.x = xy[0];
15589             s.y = xy[1];
15590         }
15591         return s;
15592     },
15593
15594     /**
15595      * Sets the current box measurements of the component's underlying element.
15596      * @param {Object} box An object in the format {x, y, width, height}
15597      * @returns {Roo.BoxComponent} this
15598      */
15599     updateBox : function(box){
15600         this.setSize(box.width, box.height);
15601         this.setPagePosition(box.x, box.y);
15602         return this;
15603     },
15604
15605     // protected
15606     getResizeEl : function(){
15607         return this.resizeEl || this.el;
15608     },
15609
15610     // protected
15611     getPositionEl : function(){
15612         return this.positionEl || this.el;
15613     },
15614
15615     /**
15616      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15617      * This method fires the move event.
15618      * @param {Number} left The new left
15619      * @param {Number} top The new top
15620      * @returns {Roo.BoxComponent} this
15621      */
15622     setPosition : function(x, y){
15623         this.x = x;
15624         this.y = y;
15625         if(!this.boxReady){
15626             return this;
15627         }
15628         var adj = this.adjustPosition(x, y);
15629         var ax = adj.x, ay = adj.y;
15630
15631         var el = this.getPositionEl();
15632         if(ax !== undefined || ay !== undefined){
15633             if(ax !== undefined && ay !== undefined){
15634                 el.setLeftTop(ax, ay);
15635             }else if(ax !== undefined){
15636                 el.setLeft(ax);
15637             }else if(ay !== undefined){
15638                 el.setTop(ay);
15639             }
15640             this.onPosition(ax, ay);
15641             this.fireEvent('move', this, ax, ay);
15642         }
15643         return this;
15644     },
15645
15646     /**
15647      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15648      * This method fires the move event.
15649      * @param {Number} x The new x position
15650      * @param {Number} y The new y position
15651      * @returns {Roo.BoxComponent} this
15652      */
15653     setPagePosition : function(x, y){
15654         this.pageX = x;
15655         this.pageY = y;
15656         if(!this.boxReady){
15657             return;
15658         }
15659         if(x === undefined || y === undefined){ // cannot translate undefined points
15660             return;
15661         }
15662         var p = this.el.translatePoints(x, y);
15663         this.setPosition(p.left, p.top);
15664         return this;
15665     },
15666
15667     // private
15668     onRender : function(ct, position){
15669         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15670         if(this.resizeEl){
15671             this.resizeEl = Roo.get(this.resizeEl);
15672         }
15673         if(this.positionEl){
15674             this.positionEl = Roo.get(this.positionEl);
15675         }
15676     },
15677
15678     // private
15679     afterRender : function(){
15680         Roo.BoxComponent.superclass.afterRender.call(this);
15681         this.boxReady = true;
15682         this.setSize(this.width, this.height);
15683         if(this.x || this.y){
15684             this.setPosition(this.x, this.y);
15685         }
15686         if(this.pageX || this.pageY){
15687             this.setPagePosition(this.pageX, this.pageY);
15688         }
15689     },
15690
15691     /**
15692      * Force the component's size to recalculate based on the underlying element's current height and width.
15693      * @returns {Roo.BoxComponent} this
15694      */
15695     syncSize : function(){
15696         delete this.lastSize;
15697         this.setSize(this.el.getWidth(), this.el.getHeight());
15698         return this;
15699     },
15700
15701     /**
15702      * Called after the component is resized, this method is empty by default but can be implemented by any
15703      * subclass that needs to perform custom logic after a resize occurs.
15704      * @param {Number} adjWidth The box-adjusted width that was set
15705      * @param {Number} adjHeight The box-adjusted height that was set
15706      * @param {Number} rawWidth The width that was originally specified
15707      * @param {Number} rawHeight The height that was originally specified
15708      */
15709     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15710
15711     },
15712
15713     /**
15714      * Called after the component is moved, this method is empty by default but can be implemented by any
15715      * subclass that needs to perform custom logic after a move occurs.
15716      * @param {Number} x The new x position
15717      * @param {Number} y The new y position
15718      */
15719     onPosition : function(x, y){
15720
15721     },
15722
15723     // private
15724     adjustSize : function(w, h){
15725         if(this.autoWidth){
15726             w = 'auto';
15727         }
15728         if(this.autoHeight){
15729             h = 'auto';
15730         }
15731         return {width : w, height: h};
15732     },
15733
15734     // private
15735     adjustPosition : function(x, y){
15736         return {x : x, y: y};
15737     }
15738 });/*
15739  * Original code for Roojs - LGPL
15740  * <script type="text/javascript">
15741  */
15742  
15743 /**
15744  * @class Roo.XComponent
15745  * A delayed Element creator...
15746  * Or a way to group chunks of interface together.
15747  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15748  *  used in conjunction with XComponent.build() it will create an instance of each element,
15749  *  then call addxtype() to build the User interface.
15750  * 
15751  * Mypart.xyx = new Roo.XComponent({
15752
15753     parent : 'Mypart.xyz', // empty == document.element.!!
15754     order : '001',
15755     name : 'xxxx'
15756     region : 'xxxx'
15757     disabled : function() {} 
15758      
15759     tree : function() { // return an tree of xtype declared components
15760         var MODULE = this;
15761         return 
15762         {
15763             xtype : 'NestedLayoutPanel',
15764             // technicall
15765         }
15766      ]
15767  *})
15768  *
15769  *
15770  * It can be used to build a big heiracy, with parent etc.
15771  * or you can just use this to render a single compoent to a dom element
15772  * MYPART.render(Roo.Element | String(id) | dom_element )
15773  *
15774  *
15775  * Usage patterns.
15776  *
15777  * Classic Roo
15778  *
15779  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15780  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15781  *
15782  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15783  *
15784  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15785  * - if mulitple topModules exist, the last one is defined as the top module.
15786  *
15787  * Embeded Roo
15788  * 
15789  * When the top level or multiple modules are to embedded into a existing HTML page,
15790  * the parent element can container '#id' of the element where the module will be drawn.
15791  *
15792  * Bootstrap Roo
15793  *
15794  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15795  * it relies more on a include mechanism, where sub modules are included into an outer page.
15796  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15797  * 
15798  * Bootstrap Roo Included elements
15799  *
15800  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15801  * hence confusing the component builder as it thinks there are multiple top level elements. 
15802  *
15803  * 
15804  * 
15805  * @extends Roo.util.Observable
15806  * @constructor
15807  * @param cfg {Object} configuration of component
15808  * 
15809  */
15810 Roo.XComponent = function(cfg) {
15811     Roo.apply(this, cfg);
15812     this.addEvents({ 
15813         /**
15814              * @event built
15815              * Fires when this the componnt is built
15816              * @param {Roo.XComponent} c the component
15817              */
15818         'built' : true
15819         
15820     });
15821     this.region = this.region || 'center'; // default..
15822     Roo.XComponent.register(this);
15823     this.modules = false;
15824     this.el = false; // where the layout goes..
15825     
15826     
15827 }
15828 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15829     /**
15830      * @property el
15831      * The created element (with Roo.factory())
15832      * @type {Roo.Layout}
15833      */
15834     el  : false,
15835     
15836     /**
15837      * @property el
15838      * for BC  - use el in new code
15839      * @type {Roo.Layout}
15840      */
15841     panel : false,
15842     
15843     /**
15844      * @property layout
15845      * for BC  - use el in new code
15846      * @type {Roo.Layout}
15847      */
15848     layout : false,
15849     
15850      /**
15851      * @cfg {Function|boolean} disabled
15852      * If this module is disabled by some rule, return true from the funtion
15853      */
15854     disabled : false,
15855     
15856     /**
15857      * @cfg {String} parent 
15858      * Name of parent element which it get xtype added to..
15859      */
15860     parent: false,
15861     
15862     /**
15863      * @cfg {String} order
15864      * Used to set the order in which elements are created (usefull for multiple tabs)
15865      */
15866     
15867     order : false,
15868     /**
15869      * @cfg {String} name
15870      * String to display while loading.
15871      */
15872     name : false,
15873     /**
15874      * @cfg {String} region
15875      * Region to render component to (defaults to center)
15876      */
15877     region : 'center',
15878     
15879     /**
15880      * @cfg {Array} items
15881      * A single item array - the first element is the root of the tree..
15882      * It's done this way to stay compatible with the Xtype system...
15883      */
15884     items : false,
15885     
15886     /**
15887      * @property _tree
15888      * The method that retuns the tree of parts that make up this compoennt 
15889      * @type {function}
15890      */
15891     _tree  : false,
15892     
15893      /**
15894      * render
15895      * render element to dom or tree
15896      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15897      */
15898     
15899     render : function(el)
15900     {
15901         
15902         el = el || false;
15903         var hp = this.parent ? 1 : 0;
15904         Roo.log(this);
15905         
15906         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15907             // if parent is a '#.....' string, then let's use that..
15908             var ename = this.parent.substr(1);
15909             this.parent = false;
15910             Roo.log(ename);
15911             switch (ename) {
15912                 case 'bootstrap-body' :
15913                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15914                         this.parent = { el :  new  Roo.bootstrap.Body() };
15915                         Roo.log("setting el to doc body");
15916                          
15917                     } else {
15918                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15919                     }
15920                     break;
15921                 case 'bootstrap':
15922                     this.parent = { el : true};
15923                     // fall through
15924                 default:
15925                     el = Roo.get(ename);
15926                     break;
15927             }
15928                 
15929             
15930             if (!el && !this.parent) {
15931                 Roo.log("Warning - element can not be found :#" + ename );
15932                 return;
15933             }
15934         }
15935         Roo.log("EL:");Roo.log(el);
15936         Roo.log("this.parent.el:");Roo.log(this.parent.el);
15937         
15938         var tree = this._tree ? this._tree() : this.tree();
15939
15940         // altertive root elements ??? - we need a better way to indicate these.
15941         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15942                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15943         
15944         if (!this.parent && is_alt) {
15945             //el = Roo.get(document.body);
15946             this.parent = { el : true };
15947         }
15948             
15949             
15950         
15951         if (!this.parent) {
15952             
15953             Roo.log("no parent - creating one");
15954             
15955             el = el ? Roo.get(el) : false;      
15956             
15957             // it's a top level one..
15958             this.parent =  {
15959                 el : new Roo.BorderLayout(el || document.body, {
15960                 
15961                      center: {
15962                          titlebar: false,
15963                          autoScroll:false,
15964                          closeOnTab: true,
15965                          tabPosition: 'top',
15966                           //resizeTabs: true,
15967                          alwaysShowTabs: el && hp? false :  true,
15968                          hideTabs: el || !hp ? true :  false,
15969                          minTabWidth: 140
15970                      }
15971                  })
15972             }
15973         }
15974         
15975                 if (!this.parent.el) {
15976                         // probably an old style ctor, which has been disabled.
15977                         return;
15978                         
15979                 }
15980                 // The 'tree' method is  '_tree now' 
15981             
15982         tree.region = tree.region || this.region;
15983         
15984         if (this.parent.el === true) {
15985             // bootstrap... - body..
15986             this.parent.el = Roo.factory(tree);
15987         }
15988         
15989         this.el = this.parent.el.addxtype(tree);
15990         this.fireEvent('built', this);
15991         
15992         this.panel = this.el;
15993         this.layout = this.panel.layout;
15994                 this.parentLayout = this.parent.layout  || false;  
15995          
15996     }
15997     
15998 });
15999
16000 Roo.apply(Roo.XComponent, {
16001     /**
16002      * @property  hideProgress
16003      * true to disable the building progress bar.. usefull on single page renders.
16004      * @type Boolean
16005      */
16006     hideProgress : false,
16007     /**
16008      * @property  buildCompleted
16009      * True when the builder has completed building the interface.
16010      * @type Boolean
16011      */
16012     buildCompleted : false,
16013      
16014     /**
16015      * @property  topModule
16016      * the upper most module - uses document.element as it's constructor.
16017      * @type Object
16018      */
16019      
16020     topModule  : false,
16021       
16022     /**
16023      * @property  modules
16024      * array of modules to be created by registration system.
16025      * @type {Array} of Roo.XComponent
16026      */
16027     
16028     modules : [],
16029     /**
16030      * @property  elmodules
16031      * array of modules to be created by which use #ID 
16032      * @type {Array} of Roo.XComponent
16033      */
16034      
16035     elmodules : [],
16036
16037      /**
16038      * @property  build_from_html
16039      * Build elements from html - used by bootstrap HTML stuff 
16040      *    - this is cleared after build is completed
16041      * @type {boolean} true  (default false)
16042      */
16043      
16044     build_from_html : false,
16045
16046     /**
16047      * Register components to be built later.
16048      *
16049      * This solves the following issues
16050      * - Building is not done on page load, but after an authentication process has occured.
16051      * - Interface elements are registered on page load
16052      * - Parent Interface elements may not be loaded before child, so this handles that..
16053      * 
16054      *
16055      * example:
16056      * 
16057      * MyApp.register({
16058           order : '000001',
16059           module : 'Pman.Tab.projectMgr',
16060           region : 'center',
16061           parent : 'Pman.layout',
16062           disabled : false,  // or use a function..
16063         })
16064      
16065      * * @param {Object} details about module
16066      */
16067     register : function(obj) {
16068                 
16069         Roo.XComponent.event.fireEvent('register', obj);
16070         switch(typeof(obj.disabled) ) {
16071                 
16072             case 'undefined':
16073                 break;
16074             
16075             case 'function':
16076                 if ( obj.disabled() ) {
16077                         return;
16078                 }
16079                 break;
16080             
16081             default:
16082                 if (obj.disabled) {
16083                         return;
16084                 }
16085                 break;
16086         }
16087                 
16088         this.modules.push(obj);
16089          
16090     },
16091     /**
16092      * convert a string to an object..
16093      * eg. 'AAA.BBB' -> finds AAA.BBB
16094
16095      */
16096     
16097     toObject : function(str)
16098     {
16099         if (!str || typeof(str) == 'object') {
16100             return str;
16101         }
16102         if (str.substring(0,1) == '#') {
16103             return str;
16104         }
16105
16106         var ar = str.split('.');
16107         var rt, o;
16108         rt = ar.shift();
16109             /** eval:var:o */
16110         try {
16111             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16112         } catch (e) {
16113             throw "Module not found : " + str;
16114         }
16115         
16116         if (o === false) {
16117             throw "Module not found : " + str;
16118         }
16119         Roo.each(ar, function(e) {
16120             if (typeof(o[e]) == 'undefined') {
16121                 throw "Module not found : " + str;
16122             }
16123             o = o[e];
16124         });
16125         
16126         return o;
16127         
16128     },
16129     
16130     
16131     /**
16132      * move modules into their correct place in the tree..
16133      * 
16134      */
16135     preBuild : function ()
16136     {
16137         var _t = this;
16138         Roo.each(this.modules , function (obj)
16139         {
16140             Roo.XComponent.event.fireEvent('beforebuild', obj);
16141             
16142             var opar = obj.parent;
16143             try { 
16144                 obj.parent = this.toObject(opar);
16145             } catch(e) {
16146                 Roo.log("parent:toObject failed: " + e.toString());
16147                 return;
16148             }
16149             
16150             if (!obj.parent) {
16151                 Roo.debug && Roo.log("GOT top level module");
16152                 Roo.debug && Roo.log(obj);
16153                 obj.modules = new Roo.util.MixedCollection(false, 
16154                     function(o) { return o.order + '' }
16155                 );
16156                 this.topModule = obj;
16157                 return;
16158             }
16159                         // parent is a string (usually a dom element name..)
16160             if (typeof(obj.parent) == 'string') {
16161                 this.elmodules.push(obj);
16162                 return;
16163             }
16164             if (obj.parent.constructor != Roo.XComponent) {
16165                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16166             }
16167             if (!obj.parent.modules) {
16168                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16169                     function(o) { return o.order + '' }
16170                 );
16171             }
16172             if (obj.parent.disabled) {
16173                 obj.disabled = true;
16174             }
16175             obj.parent.modules.add(obj);
16176         }, this);
16177     },
16178     
16179      /**
16180      * make a list of modules to build.
16181      * @return {Array} list of modules. 
16182      */ 
16183     
16184     buildOrder : function()
16185     {
16186         var _this = this;
16187         var cmp = function(a,b) {   
16188             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16189         };
16190         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16191             throw "No top level modules to build";
16192         }
16193         
16194         // make a flat list in order of modules to build.
16195         var mods = this.topModule ? [ this.topModule ] : [];
16196                 
16197         
16198         // elmodules (is a list of DOM based modules )
16199         Roo.each(this.elmodules, function(e) {
16200             mods.push(e);
16201             if (!this.topModule &&
16202                 typeof(e.parent) == 'string' &&
16203                 e.parent.substring(0,1) == '#' &&
16204                 Roo.get(e.parent.substr(1))
16205                ) {
16206                 
16207                 _this.topModule = e;
16208             }
16209             
16210         });
16211
16212         
16213         // add modules to their parents..
16214         var addMod = function(m) {
16215             Roo.debug && Roo.log("build Order: add: " + m.name);
16216                 
16217             mods.push(m);
16218             if (m.modules && !m.disabled) {
16219                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16220                 m.modules.keySort('ASC',  cmp );
16221                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16222     
16223                 m.modules.each(addMod);
16224             } else {
16225                 Roo.debug && Roo.log("build Order: no child modules");
16226             }
16227             // not sure if this is used any more..
16228             if (m.finalize) {
16229                 m.finalize.name = m.name + " (clean up) ";
16230                 mods.push(m.finalize);
16231             }
16232             
16233         }
16234         if (this.topModule && this.topModule.modules) { 
16235             this.topModule.modules.keySort('ASC',  cmp );
16236             this.topModule.modules.each(addMod);
16237         } 
16238         return mods;
16239     },
16240     
16241      /**
16242      * Build the registered modules.
16243      * @param {Object} parent element.
16244      * @param {Function} optional method to call after module has been added.
16245      * 
16246      */ 
16247    
16248     build : function(opts) 
16249     {
16250         
16251         if (typeof(opts) != 'undefined') {
16252             Roo.apply(this,opts);
16253         }
16254         
16255         this.preBuild();
16256         var mods = this.buildOrder();
16257       
16258         //this.allmods = mods;
16259         //Roo.debug && Roo.log(mods);
16260         //return;
16261         if (!mods.length) { // should not happen
16262             throw "NO modules!!!";
16263         }
16264         
16265         
16266         var msg = "Building Interface...";
16267         // flash it up as modal - so we store the mask!?
16268         if (!this.hideProgress && Roo.MessageBox) {
16269             Roo.MessageBox.show({ title: 'loading' });
16270             Roo.MessageBox.show({
16271                title: "Please wait...",
16272                msg: msg,
16273                width:450,
16274                progress:true,
16275                closable:false,
16276                modal: false
16277               
16278             });
16279         }
16280         var total = mods.length;
16281         
16282         var _this = this;
16283         var progressRun = function() {
16284             if (!mods.length) {
16285                 Roo.debug && Roo.log('hide?');
16286                 if (!this.hideProgress && Roo.MessageBox) {
16287                     Roo.MessageBox.hide();
16288                 }
16289                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16290                 
16291                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16292                 
16293                 // THE END...
16294                 return false;   
16295             }
16296             
16297             var m = mods.shift();
16298             
16299             
16300             Roo.debug && Roo.log(m);
16301             // not sure if this is supported any more.. - modules that are are just function
16302             if (typeof(m) == 'function') { 
16303                 m.call(this);
16304                 return progressRun.defer(10, _this);
16305             } 
16306             
16307             
16308             msg = "Building Interface " + (total  - mods.length) + 
16309                     " of " + total + 
16310                     (m.name ? (' - ' + m.name) : '');
16311                         Roo.debug && Roo.log(msg);
16312             if (!this.hideProgress &&  Roo.MessageBox) { 
16313                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16314             }
16315             
16316          
16317             // is the module disabled?
16318             var disabled = (typeof(m.disabled) == 'function') ?
16319                 m.disabled.call(m.module.disabled) : m.disabled;    
16320             
16321             
16322             if (disabled) {
16323                 return progressRun(); // we do not update the display!
16324             }
16325             
16326             // now build 
16327             
16328                         
16329                         
16330             m.render();
16331             // it's 10 on top level, and 1 on others??? why...
16332             return progressRun.defer(10, _this);
16333              
16334         }
16335         progressRun.defer(1, _this);
16336      
16337         
16338         
16339     },
16340         
16341         
16342         /**
16343          * Event Object.
16344          *
16345          *
16346          */
16347         event: false, 
16348     /**
16349          * wrapper for event.on - aliased later..  
16350          * Typically use to register a event handler for register:
16351          *
16352          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16353          *
16354          */
16355     on : false
16356    
16357     
16358     
16359 });
16360
16361 Roo.XComponent.event = new Roo.util.Observable({
16362                 events : { 
16363                         /**
16364                          * @event register
16365                          * Fires when an Component is registered,
16366                          * set the disable property on the Component to stop registration.
16367                          * @param {Roo.XComponent} c the component being registerd.
16368                          * 
16369                          */
16370                         'register' : true,
16371             /**
16372                          * @event beforebuild
16373                          * Fires before each Component is built
16374                          * can be used to apply permissions.
16375                          * @param {Roo.XComponent} c the component being registerd.
16376                          * 
16377                          */
16378                         'beforebuild' : true,
16379                         /**
16380                          * @event buildcomplete
16381                          * Fires on the top level element when all elements have been built
16382                          * @param {Roo.XComponent} the top level component.
16383                          */
16384                         'buildcomplete' : true
16385                         
16386                 }
16387 });
16388
16389 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16390