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         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iPhone|iPad\./.test(ua),
67         isTouch =  (function() {
68             try {  
69                 document.createEvent("TouchEvent");  
70                 return true;  
71             } catch (e) {  
72                 return false;  
73             } 
74             
75         })();
76     // remove css image flicker
77         if(isIE && !isIE7){
78         try{
79             document.execCommand("BackgroundImageCache", false, true);
80         }catch(e){}
81     }
82     
83     Roo.apply(Roo, {
84         /**
85          * True if the browser is in strict mode
86          * @type Boolean
87          */
88         isStrict : isStrict,
89         /**
90          * True if the page is running over SSL
91          * @type Boolean
92          */
93         isSecure : isSecure,
94         /**
95          * True when the document is fully initialized and ready for action
96          * @type Boolean
97          */
98         isReady : false,
99         /**
100          * Turn on debugging output (currently only the factory uses this)
101          * @type Boolean
102          */
103         
104         debug: false,
105
106         /**
107          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
108          * @type Boolean
109          */
110         enableGarbageCollector : true,
111
112         /**
113          * True to automatically purge event listeners after uncaching an element (defaults to false).
114          * Note: this only happens if enableGarbageCollector is true.
115          * @type Boolean
116          */
117         enableListenerCollection:false,
118
119         /**
120          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121          * the IE insecure content warning (defaults to javascript:false).
122          * @type String
123          */
124         SSL_SECURE_URL : "javascript:false",
125
126         /**
127          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
129          * @type String
130          */
131         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
132
133         emptyFn : function(){},
134         
135         /**
136          * Copies all the properties of config to obj if they don't already exist.
137          * @param {Object} obj The receiver of the properties
138          * @param {Object} config The source of the properties
139          * @return {Object} returns obj
140          */
141         applyIf : function(o, c){
142             if(o && c){
143                 for(var p in c){
144                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
145                 }
146             }
147             return o;
148         },
149
150         /**
151          * Applies event listeners to elements by selectors when the document is ready.
152          * The event name is specified with an @ suffix.
153 <pre><code>
154 Roo.addBehaviors({
155    // add a listener for click on all anchors in element with id foo
156    '#foo a@click' : function(e, t){
157        // do something
158    },
159
160    // add the same listener to multiple selectors (separated by comma BEFORE the @)
161    '#foo a, #bar span.some-class@mouseover' : function(){
162        // do something
163    }
164 });
165 </code></pre>
166          * @param {Object} obj The list of behaviors to apply
167          */
168         addBehaviors : function(o){
169             if(!Roo.isReady){
170                 Roo.onReady(function(){
171                     Roo.addBehaviors(o);
172                 });
173                 return;
174             }
175             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
176             for(var b in o){
177                 var parts = b.split('@');
178                 if(parts[1]){ // for Object prototype breakers
179                     var s = parts[0];
180                     if(!cache[s]){
181                         cache[s] = Roo.select(s);
182                     }
183                     cache[s].on(parts[1], o[b]);
184                 }
185             }
186             cache = null;
187         },
188
189         /**
190          * Generates unique ids. If the element already has an id, it is unchanged
191          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193          * @return {String} The generated Id.
194          */
195         id : function(el, prefix){
196             prefix = prefix || "roo-gen";
197             el = Roo.getDom(el);
198             var id = prefix + (++idSeed);
199             return el ? (el.id ? el.id : (el.id = id)) : id;
200         },
201          
202        
203         /**
204          * Extends one class with another class and optionally overrides members with the passed literal. This class
205          * also adds the function "override()" to the class that can be used to override
206          * members on an instance.
207          * @param {Object} subclass The class inheriting the functionality
208          * @param {Object} superclass The class being extended
209          * @param {Object} overrides (optional) A literal with members
210          * @method extend
211          */
212         extend : function(){
213             // inline overrides
214             var io = function(o){
215                 for(var m in o){
216                     this[m] = o[m];
217                 }
218             };
219             return function(sb, sp, overrides){
220                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
221                     overrides = sp;
222                     sp = sb;
223                     sb = function(){sp.apply(this, arguments);};
224                 }
225                 var F = function(){}, sbp, spp = sp.prototype;
226                 F.prototype = spp;
227                 sbp = sb.prototype = new F();
228                 sbp.constructor=sb;
229                 sb.superclass=spp;
230                 
231                 if(spp.constructor == Object.prototype.constructor){
232                     spp.constructor=sp;
233                    
234                 }
235                 
236                 sb.override = function(o){
237                     Roo.override(sb, o);
238                 };
239                 sbp.override = io;
240                 Roo.override(sb, overrides);
241                 return sb;
242             };
243         }(),
244
245         /**
246          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
247          * Usage:<pre><code>
248 Roo.override(MyClass, {
249     newMethod1: function(){
250         // etc.
251     },
252     newMethod2: function(foo){
253         // etc.
254     }
255 });
256  </code></pre>
257          * @param {Object} origclass The class to override
258          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
259          * containing one or more methods.
260          * @method override
261          */
262         override : function(origclass, overrides){
263             if(overrides){
264                 var p = origclass.prototype;
265                 for(var method in overrides){
266                     p[method] = overrides[method];
267                 }
268             }
269         },
270         /**
271          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
272          * <pre><code>
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
276 </code></pre>
277          * @param {String} namespace1
278          * @param {String} namespace2
279          * @param {String} etc
280          * @method namespace
281          */
282         namespace : function(){
283             var a=arguments, o=null, i, j, d, rt;
284             for (i=0; i<a.length; ++i) {
285                 d=a[i].split(".");
286                 rt = d[0];
287                 /** eval:var:o */
288                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289                 for (j=1; j<d.length; ++j) {
290                     o[d[j]]=o[d[j]] || {};
291                     o=o[d[j]];
292                 }
293             }
294         },
295         /**
296          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
297          * <pre><code>
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
300 </code></pre>
301          * @param {String} classname
302          * @param {String} namespace (optional)
303          * @method factory
304          */
305          
306         factory : function(c, ns)
307         {
308             // no xtype, no ns or c.xns - or forced off by c.xns
309             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
310                 return c;
311             }
312             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313             if (c.constructor == ns[c.xtype]) {// already created...
314                 return c;
315             }
316             if (ns[c.xtype]) {
317                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
318                 var ret = new ns[c.xtype](c);
319                 ret.xns = false;
320                 return ret;
321             }
322             c.xns = false; // prevent recursion..
323             return c;
324         },
325          /**
326          * Logs to console if it can.
327          *
328          * @param {String|Object} string
329          * @method log
330          */
331         log : function(s)
332         {
333             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
334                 return; // alerT?
335             }
336             console.log(s);
337             
338         },
339         /**
340          * 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.
341          * @param {Object} o
342          * @return {String}
343          */
344         urlEncode : function(o){
345             if(!o){
346                 return "";
347             }
348             var buf = [];
349             for(var key in o){
350                 var ov = o[key], k = Roo.encodeURIComponent(key);
351                 var type = typeof ov;
352                 if(type == 'undefined'){
353                     buf.push(k, "=&");
354                 }else if(type != "function" && type != "object"){
355                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356                 }else if(ov instanceof Array){
357                     if (ov.length) {
358                             for(var i = 0, len = ov.length; i < len; i++) {
359                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
360                             }
361                         } else {
362                             buf.push(k, "=&");
363                         }
364                 }
365             }
366             buf.pop();
367             return buf.join("");
368         },
369          /**
370          * Safe version of encodeURIComponent
371          * @param {String} data 
372          * @return {String} 
373          */
374         
375         encodeURIComponent : function (data)
376         {
377             try {
378                 return encodeURIComponent(data);
379             } catch(e) {} // should be an uri encode error.
380             
381             if (data == '' || data == null){
382                return '';
383             }
384             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385             function nibble_to_hex(nibble){
386                 var chars = '0123456789ABCDEF';
387                 return chars.charAt(nibble);
388             }
389             data = data.toString();
390             var buffer = '';
391             for(var i=0; i<data.length; i++){
392                 var c = data.charCodeAt(i);
393                 var bs = new Array();
394                 if (c > 0x10000){
395                         // 4 bytes
396                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399                     bs[3] = 0x80 | (c & 0x3F);
400                 }else if (c > 0x800){
401                          // 3 bytes
402                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404                     bs[2] = 0x80 | (c & 0x3F);
405                 }else if (c > 0x80){
406                        // 2 bytes
407                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408                     bs[1] = 0x80 | (c & 0x3F);
409                 }else{
410                         // 1 byte
411                     bs[0] = c;
412                 }
413                 for(var j=0; j<bs.length; j++){
414                     var b = bs[j];
415                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
416                             + nibble_to_hex(b &0x0F);
417                     buffer += '%'+hex;
418                }
419             }
420             return buffer;    
421              
422         },
423
424         /**
425          * 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]}.
426          * @param {String} string
427          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428          * @return {Object} A literal with members
429          */
430         urlDecode : function(string, overwrite){
431             if(!string || !string.length){
432                 return {};
433             }
434             var obj = {};
435             var pairs = string.split('&');
436             var pair, name, value;
437             for(var i = 0, len = pairs.length; i < len; i++){
438                 pair = pairs[i].split('=');
439                 name = decodeURIComponent(pair[0]);
440                 value = decodeURIComponent(pair[1]);
441                 if(overwrite !== true){
442                     if(typeof obj[name] == "undefined"){
443                         obj[name] = value;
444                     }else if(typeof obj[name] == "string"){
445                         obj[name] = [obj[name]];
446                         obj[name].push(value);
447                     }else{
448                         obj[name].push(value);
449                     }
450                 }else{
451                     obj[name] = value;
452                 }
453             }
454             return obj;
455         },
456
457         /**
458          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459          * passed array is not really an array, your function is called once with it.
460          * The supplied function is called with (Object item, Number index, Array allItems).
461          * @param {Array/NodeList/Mixed} array
462          * @param {Function} fn
463          * @param {Object} scope
464          */
465         each : function(array, fn, scope){
466             if(typeof array.length == "undefined" || typeof array == "string"){
467                 array = [array];
468             }
469             for(var i = 0, len = array.length; i < len; i++){
470                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
471             }
472         },
473
474         // deprecated
475         combine : function(){
476             var as = arguments, l = as.length, r = [];
477             for(var i = 0; i < l; i++){
478                 var a = as[i];
479                 if(a instanceof Array){
480                     r = r.concat(a);
481                 }else if(a.length !== undefined && !a.substr){
482                     r = r.concat(Array.prototype.slice.call(a, 0));
483                 }else{
484                     r.push(a);
485                 }
486             }
487             return r;
488         },
489
490         /**
491          * Escapes the passed string for use in a regular expression
492          * @param {String} str
493          * @return {String}
494          */
495         escapeRe : function(s) {
496             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
497         },
498
499         // internal
500         callback : function(cb, scope, args, delay){
501             if(typeof cb == "function"){
502                 if(delay){
503                     cb.defer(delay, scope, args || []);
504                 }else{
505                     cb.apply(scope, args || []);
506                 }
507             }
508         },
509
510         /**
511          * Return the dom node for the passed string (id), dom node, or Roo.Element
512          * @param {String/HTMLElement/Roo.Element} el
513          * @return HTMLElement
514          */
515         getDom : function(el){
516             if(!el){
517                 return null;
518             }
519             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
520         },
521
522         /**
523         * Shorthand for {@link Roo.ComponentMgr#get}
524         * @param {String} id
525         * @return Roo.Component
526         */
527         getCmp : function(id){
528             return Roo.ComponentMgr.get(id);
529         },
530          
531         num : function(v, defaultValue){
532             if(typeof v != 'number'){
533                 return defaultValue;
534             }
535             return v;
536         },
537
538         destroy : function(){
539             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
540                 var as = a[i];
541                 if(as){
542                     if(as.dom){
543                         as.removeAllListeners();
544                         as.remove();
545                         continue;
546                     }
547                     if(typeof as.purgeListeners == 'function'){
548                         as.purgeListeners();
549                     }
550                     if(typeof as.destroy == 'function'){
551                         as.destroy();
552                     }
553                 }
554             }
555         },
556
557         // inpired by a similar function in mootools library
558         /**
559          * Returns the type of object that is passed in. If the object passed in is null or undefined it
560          * return false otherwise it returns one of the following values:<ul>
561          * <li><b>string</b>: If the object passed is a string</li>
562          * <li><b>number</b>: If the object passed is a number</li>
563          * <li><b>boolean</b>: If the object passed is a boolean value</li>
564          * <li><b>function</b>: If the object passed is a function reference</li>
565          * <li><b>object</b>: If the object passed is an object</li>
566          * <li><b>array</b>: If the object passed is an array</li>
567          * <li><b>regexp</b>: If the object passed is a regular expression</li>
568          * <li><b>element</b>: If the object passed is a DOM Element</li>
569          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572          * @param {Mixed} object
573          * @return {String}
574          */
575         type : function(o){
576             if(o === undefined || o === null){
577                 return false;
578             }
579             if(o.htmlElement){
580                 return 'element';
581             }
582             var t = typeof o;
583             if(t == 'object' && o.nodeName) {
584                 switch(o.nodeType) {
585                     case 1: return 'element';
586                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
587                 }
588             }
589             if(t == 'object' || t == 'function') {
590                 switch(o.constructor) {
591                     case Array: return 'array';
592                     case RegExp: return 'regexp';
593                 }
594                 if(typeof o.length == 'number' && typeof o.item == 'function') {
595                     return 'nodelist';
596                 }
597             }
598             return t;
599         },
600
601         /**
602          * Returns true if the passed value is null, undefined or an empty string (optional).
603          * @param {Mixed} value The value to test
604          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
605          * @return {Boolean}
606          */
607         isEmpty : function(v, allowBlank){
608             return v === null || v === undefined || (!allowBlank ? v === '' : false);
609         },
610         
611         /** @type Boolean */
612         isOpera : isOpera,
613         /** @type Boolean */
614         isSafari : isSafari,
615         /** @type Boolean */
616         isFirefox : isFirefox,
617         /** @type Boolean */
618         isIE : isIE,
619         /** @type Boolean */
620         isIE7 : isIE7,
621         /** @type Boolean */
622         isIE11 : isIE11,
623         /** @type Boolean */
624         isGecko : isGecko,
625         /** @type Boolean */
626         isBorderBox : isBorderBox,
627         /** @type Boolean */
628         isWindows : isWindows,
629         /** @type Boolean */
630         isLinux : isLinux,
631         /** @type Boolean */
632         isMac : isMac,
633         /** @type Boolean */
634         isTouch : isTouch,
635
636         /**
637          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
638          * you may want to set this to true.
639          * @type Boolean
640          */
641         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
642         
643         
644                 
645         /**
646          * Selects a single element as a Roo Element
647          * This is about as close as you can get to jQuery's $('do crazy stuff')
648          * @param {String} selector The selector/xpath query
649          * @param {Node} root (optional) The start of the query (defaults to document).
650          * @return {Roo.Element}
651          */
652         selectNode : function(selector, root) 
653         {
654             var node = Roo.DomQuery.selectNode(selector,root);
655             return node ? Roo.get(node) : new Roo.Element(false);
656         }
657         
658     });
659
660
661 })();
662
663 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
664                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
665                 "Roo.app", "Roo.ux",
666                 "Roo.bootstrap",
667                 "Roo.bootstrap.dash");
668 /*
669  * Based on:
670  * Ext JS Library 1.1.1
671  * Copyright(c) 2006-2007, Ext JS, LLC.
672  *
673  * Originally Released Under LGPL - original licence link has changed is not relivant.
674  *
675  * Fork - LGPL
676  * <script type="text/javascript">
677  */
678
679 (function() {    
680     // wrappedn so fnCleanup is not in global scope...
681     if(Roo.isIE) {
682         function fnCleanUp() {
683             var p = Function.prototype;
684             delete p.createSequence;
685             delete p.defer;
686             delete p.createDelegate;
687             delete p.createCallback;
688             delete p.createInterceptor;
689
690             window.detachEvent("onunload", fnCleanUp);
691         }
692         window.attachEvent("onunload", fnCleanUp);
693     }
694 })();
695
696
697 /**
698  * @class Function
699  * These functions are available on every Function object (any JavaScript function).
700  */
701 Roo.apply(Function.prototype, {
702      /**
703      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
704      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
705      * Will create a function that is bound to those 2 args.
706      * @return {Function} The new function
707     */
708     createCallback : function(/*args...*/){
709         // make args available, in function below
710         var args = arguments;
711         var method = this;
712         return function() {
713             return method.apply(window, args);
714         };
715     },
716
717     /**
718      * Creates a delegate (callback) that sets the scope to obj.
719      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
720      * Will create a function that is automatically scoped to this.
721      * @param {Object} obj (optional) The object for which the scope is set
722      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
723      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
724      *                                             if a number the args are inserted at the specified position
725      * @return {Function} The new function
726      */
727     createDelegate : function(obj, args, appendArgs){
728         var method = this;
729         return function() {
730             var callArgs = args || arguments;
731             if(appendArgs === true){
732                 callArgs = Array.prototype.slice.call(arguments, 0);
733                 callArgs = callArgs.concat(args);
734             }else if(typeof appendArgs == "number"){
735                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
736                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
737                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
738             }
739             return method.apply(obj || window, callArgs);
740         };
741     },
742
743     /**
744      * Calls this function after the number of millseconds specified.
745      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
746      * @param {Object} obj (optional) The object for which the scope is set
747      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
748      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
749      *                                             if a number the args are inserted at the specified position
750      * @return {Number} The timeout id that can be used with clearTimeout
751      */
752     defer : function(millis, obj, args, appendArgs){
753         var fn = this.createDelegate(obj, args, appendArgs);
754         if(millis){
755             return setTimeout(fn, millis);
756         }
757         fn();
758         return 0;
759     },
760     /**
761      * Create a combined function call sequence of the original function + the passed function.
762      * The resulting function returns the results of the original function.
763      * The passed fcn is called with the parameters of the original function
764      * @param {Function} fcn The function to sequence
765      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
766      * @return {Function} The new function
767      */
768     createSequence : function(fcn, scope){
769         if(typeof fcn != "function"){
770             return this;
771         }
772         var method = this;
773         return function() {
774             var retval = method.apply(this || window, arguments);
775             fcn.apply(scope || this || window, arguments);
776             return retval;
777         };
778     },
779
780     /**
781      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
782      * The resulting function returns the results of the original function.
783      * The passed fcn is called with the parameters of the original function.
784      * @addon
785      * @param {Function} fcn The function to call before the original
786      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
787      * @return {Function} The new function
788      */
789     createInterceptor : function(fcn, scope){
790         if(typeof fcn != "function"){
791             return this;
792         }
793         var method = this;
794         return function() {
795             fcn.target = this;
796             fcn.method = method;
797             if(fcn.apply(scope || this || window, arguments) === false){
798                 return;
799             }
800             return method.apply(this || window, arguments);
801         };
802     }
803 });
804 /*
805  * Based on:
806  * Ext JS Library 1.1.1
807  * Copyright(c) 2006-2007, Ext JS, LLC.
808  *
809  * Originally Released Under LGPL - original licence link has changed is not relivant.
810  *
811  * Fork - LGPL
812  * <script type="text/javascript">
813  */
814
815 Roo.applyIf(String, {
816     
817     /** @scope String */
818     
819     /**
820      * Escapes the passed string for ' and \
821      * @param {String} string The string to escape
822      * @return {String} The escaped string
823      * @static
824      */
825     escape : function(string) {
826         return string.replace(/('|\\)/g, "\\$1");
827     },
828
829     /**
830      * Pads the left side of a string with a specified character.  This is especially useful
831      * for normalizing number and date strings.  Example usage:
832      * <pre><code>
833 var s = String.leftPad('123', 5, '0');
834 // s now contains the string: '00123'
835 </code></pre>
836      * @param {String} string The original string
837      * @param {Number} size The total length of the output string
838      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
839      * @return {String} The padded string
840      * @static
841      */
842     leftPad : function (val, size, ch) {
843         var result = new String(val);
844         if(ch === null || ch === undefined || ch === '') {
845             ch = " ";
846         }
847         while (result.length < size) {
848             result = ch + result;
849         }
850         return result;
851     },
852
853     /**
854      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
855      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
856      * <pre><code>
857 var cls = 'my-class', text = 'Some text';
858 var s = String.format('<div class="{0}">{1}</div>', cls, text);
859 // s now contains the string: '<div class="my-class">Some text</div>'
860 </code></pre>
861      * @param {String} string The tokenized string to be formatted
862      * @param {String} value1 The value to replace token {0}
863      * @param {String} value2 Etc...
864      * @return {String} The formatted string
865      * @static
866      */
867     format : function(format){
868         var args = Array.prototype.slice.call(arguments, 1);
869         return format.replace(/\{(\d+)\}/g, function(m, i){
870             return Roo.util.Format.htmlEncode(args[i]);
871         });
872     }
873 });
874
875 /**
876  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
877  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
878  * they are already different, the first value passed in is returned.  Note that this method returns the new value
879  * but does not change the current string.
880  * <pre><code>
881 // alternate sort directions
882 sort = sort.toggle('ASC', 'DESC');
883
884 // instead of conditional logic:
885 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
886 </code></pre>
887  * @param {String} value The value to compare to the current string
888  * @param {String} other The new value to use if the string already equals the first value passed in
889  * @return {String} The new value
890  */
891  
892 String.prototype.toggle = function(value, other){
893     return this == value ? other : value;
894 };/*
895  * Based on:
896  * Ext JS Library 1.1.1
897  * Copyright(c) 2006-2007, Ext JS, LLC.
898  *
899  * Originally Released Under LGPL - original licence link has changed is not relivant.
900  *
901  * Fork - LGPL
902  * <script type="text/javascript">
903  */
904
905  /**
906  * @class Number
907  */
908 Roo.applyIf(Number.prototype, {
909     /**
910      * Checks whether or not the current number is within a desired range.  If the number is already within the
911      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
912      * exceeded.  Note that this method returns the constrained value but does not change the current number.
913      * @param {Number} min The minimum number in the range
914      * @param {Number} max The maximum number in the range
915      * @return {Number} The constrained value if outside the range, otherwise the current value
916      */
917     constrain : function(min, max){
918         return Math.min(Math.max(this, min), max);
919     }
920 });/*
921  * Based on:
922  * Ext JS Library 1.1.1
923  * Copyright(c) 2006-2007, Ext JS, LLC.
924  *
925  * Originally Released Under LGPL - original licence link has changed is not relivant.
926  *
927  * Fork - LGPL
928  * <script type="text/javascript">
929  */
930  /**
931  * @class Array
932  */
933 Roo.applyIf(Array.prototype, {
934     /**
935      * 
936      * Checks whether or not the specified object exists in the array.
937      * @param {Object} o The object to check for
938      * @return {Number} The index of o in the array (or -1 if it is not found)
939      */
940     indexOf : function(o){
941        for (var i = 0, len = this.length; i < len; i++){
942               if(this[i] == o) return i;
943        }
944            return -1;
945     },
946
947     /**
948      * Removes the specified object from the array.  If the object is not found nothing happens.
949      * @param {Object} o The object to remove
950      */
951     remove : function(o){
952        var index = this.indexOf(o);
953        if(index != -1){
954            this.splice(index, 1);
955        }
956     },
957     /**
958      * Map (JS 1.6 compatibility)
959      * @param {Function} function  to call
960      */
961     map : function(fun )
962     {
963         var len = this.length >>> 0;
964         if (typeof fun != "function")
965             throw new TypeError();
966
967         var res = new Array(len);
968         var thisp = arguments[1];
969         for (var i = 0; i < len; i++)
970         {
971             if (i in this)
972                 res[i] = fun.call(thisp, this[i], i, this);
973         }
974
975         return res;
976     }
977     
978 });
979
980
981  /*
982  * Based on:
983  * Ext JS Library 1.1.1
984  * Copyright(c) 2006-2007, Ext JS, LLC.
985  *
986  * Originally Released Under LGPL - original licence link has changed is not relivant.
987  *
988  * Fork - LGPL
989  * <script type="text/javascript">
990  */
991
992 /**
993  * @class Date
994  *
995  * The date parsing and format syntax is a subset of
996  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
997  * supported will provide results equivalent to their PHP versions.
998  *
999  * Following is the list of all currently supported formats:
1000  *<pre>
1001 Sample date:
1002 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1003
1004 Format  Output      Description
1005 ------  ----------  --------------------------------------------------------------
1006   d      10         Day of the month, 2 digits with leading zeros
1007   D      Wed        A textual representation of a day, three letters
1008   j      10         Day of the month without leading zeros
1009   l      Wednesday  A full textual representation of the day of the week
1010   S      th         English ordinal day of month suffix, 2 chars (use with j)
1011   w      3          Numeric representation of the day of the week
1012   z      9          The julian date, or day of the year (0-365)
1013   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1014   F      January    A full textual representation of the month
1015   m      01         Numeric representation of a month, with leading zeros
1016   M      Jan        Month name abbreviation, three letters
1017   n      1          Numeric representation of a month, without leading zeros
1018   t      31         Number of days in the given month
1019   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1020   Y      2007       A full numeric representation of a year, 4 digits
1021   y      07         A two digit representation of a year
1022   a      pm         Lowercase Ante meridiem and Post meridiem
1023   A      PM         Uppercase Ante meridiem and Post meridiem
1024   g      3          12-hour format of an hour without leading zeros
1025   G      15         24-hour format of an hour without leading zeros
1026   h      03         12-hour format of an hour with leading zeros
1027   H      15         24-hour format of an hour with leading zeros
1028   i      05         Minutes with leading zeros
1029   s      01         Seconds, with leading zeros
1030   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1031   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1032   T      CST        Timezone setting of the machine running the code
1033   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1034 </pre>
1035  *
1036  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1037  * <pre><code>
1038 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1039 document.write(dt.format('Y-m-d'));                         //2007-01-10
1040 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1041 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
1042  </code></pre>
1043  *
1044  * Here are some standard date/time patterns that you might find helpful.  They
1045  * are not part of the source of Date.js, but to use them you can simply copy this
1046  * block of code into any script that is included after Date.js and they will also become
1047  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1048  * <pre><code>
1049 Date.patterns = {
1050     ISO8601Long:"Y-m-d H:i:s",
1051     ISO8601Short:"Y-m-d",
1052     ShortDate: "n/j/Y",
1053     LongDate: "l, F d, Y",
1054     FullDateTime: "l, F d, Y g:i:s A",
1055     MonthDay: "F d",
1056     ShortTime: "g:i A",
1057     LongTime: "g:i:s A",
1058     SortableDateTime: "Y-m-d\\TH:i:s",
1059     UniversalSortableDateTime: "Y-m-d H:i:sO",
1060     YearMonth: "F, Y"
1061 };
1062 </code></pre>
1063  *
1064  * Example usage:
1065  * <pre><code>
1066 var dt = new Date();
1067 document.write(dt.format(Date.patterns.ShortDate));
1068  </code></pre>
1069  */
1070
1071 /*
1072  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1073  * They generate precompiled functions from date formats instead of parsing and
1074  * processing the pattern every time you format a date.  These functions are available
1075  * on every Date object (any javascript function).
1076  *
1077  * The original article and download are here:
1078  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1079  *
1080  */
1081  
1082  
1083  // was in core
1084 /**
1085  Returns the number of milliseconds between this date and date
1086  @param {Date} date (optional) Defaults to now
1087  @return {Number} The diff in milliseconds
1088  @member Date getElapsed
1089  */
1090 Date.prototype.getElapsed = function(date) {
1091         return Math.abs((date || new Date()).getTime()-this.getTime());
1092 };
1093 // was in date file..
1094
1095
1096 // private
1097 Date.parseFunctions = {count:0};
1098 // private
1099 Date.parseRegexes = [];
1100 // private
1101 Date.formatFunctions = {count:0};
1102
1103 // private
1104 Date.prototype.dateFormat = function(format) {
1105     if (Date.formatFunctions[format] == null) {
1106         Date.createNewFormat(format);
1107     }
1108     var func = Date.formatFunctions[format];
1109     return this[func]();
1110 };
1111
1112
1113 /**
1114  * Formats a date given the supplied format string
1115  * @param {String} format The format string
1116  * @return {String} The formatted date
1117  * @method
1118  */
1119 Date.prototype.format = Date.prototype.dateFormat;
1120
1121 // private
1122 Date.createNewFormat = function(format) {
1123     var funcName = "format" + Date.formatFunctions.count++;
1124     Date.formatFunctions[format] = funcName;
1125     var code = "Date.prototype." + funcName + " = function(){return ";
1126     var special = false;
1127     var ch = '';
1128     for (var i = 0; i < format.length; ++i) {
1129         ch = format.charAt(i);
1130         if (!special && ch == "\\") {
1131             special = true;
1132         }
1133         else if (special) {
1134             special = false;
1135             code += "'" + String.escape(ch) + "' + ";
1136         }
1137         else {
1138             code += Date.getFormatCode(ch);
1139         }
1140     }
1141     /** eval:var:zzzzzzzzzzzzz */
1142     eval(code.substring(0, code.length - 3) + ";}");
1143 };
1144
1145 // private
1146 Date.getFormatCode = function(character) {
1147     switch (character) {
1148     case "d":
1149         return "String.leftPad(this.getDate(), 2, '0') + ";
1150     case "D":
1151         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1152     case "j":
1153         return "this.getDate() + ";
1154     case "l":
1155         return "Date.dayNames[this.getDay()] + ";
1156     case "S":
1157         return "this.getSuffix() + ";
1158     case "w":
1159         return "this.getDay() + ";
1160     case "z":
1161         return "this.getDayOfYear() + ";
1162     case "W":
1163         return "this.getWeekOfYear() + ";
1164     case "F":
1165         return "Date.monthNames[this.getMonth()] + ";
1166     case "m":
1167         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1168     case "M":
1169         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1170     case "n":
1171         return "(this.getMonth() + 1) + ";
1172     case "t":
1173         return "this.getDaysInMonth() + ";
1174     case "L":
1175         return "(this.isLeapYear() ? 1 : 0) + ";
1176     case "Y":
1177         return "this.getFullYear() + ";
1178     case "y":
1179         return "('' + this.getFullYear()).substring(2, 4) + ";
1180     case "a":
1181         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1182     case "A":
1183         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1184     case "g":
1185         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1186     case "G":
1187         return "this.getHours() + ";
1188     case "h":
1189         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1190     case "H":
1191         return "String.leftPad(this.getHours(), 2, '0') + ";
1192     case "i":
1193         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1194     case "s":
1195         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1196     case "O":
1197         return "this.getGMTOffset() + ";
1198     case "P":
1199         return "this.getGMTColonOffset() + ";
1200     case "T":
1201         return "this.getTimezone() + ";
1202     case "Z":
1203         return "(this.getTimezoneOffset() * -60) + ";
1204     default:
1205         return "'" + String.escape(character) + "' + ";
1206     }
1207 };
1208
1209 /**
1210  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1211  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1212  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1213  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1214  * string or the parse operation will fail.
1215  * Example Usage:
1216 <pre><code>
1217 //dt = Fri May 25 2007 (current date)
1218 var dt = new Date();
1219
1220 //dt = Thu May 25 2006 (today's month/day in 2006)
1221 dt = Date.parseDate("2006", "Y");
1222
1223 //dt = Sun Jan 15 2006 (all date parts specified)
1224 dt = Date.parseDate("2006-1-15", "Y-m-d");
1225
1226 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1227 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1228 </code></pre>
1229  * @param {String} input The unparsed date as a string
1230  * @param {String} format The format the date is in
1231  * @return {Date} The parsed date
1232  * @static
1233  */
1234 Date.parseDate = function(input, format) {
1235     if (Date.parseFunctions[format] == null) {
1236         Date.createParser(format);
1237     }
1238     var func = Date.parseFunctions[format];
1239     return Date[func](input);
1240 };
1241 /**
1242  * @private
1243  */
1244
1245 Date.createParser = function(format) {
1246     var funcName = "parse" + Date.parseFunctions.count++;
1247     var regexNum = Date.parseRegexes.length;
1248     var currentGroup = 1;
1249     Date.parseFunctions[format] = funcName;
1250
1251     var code = "Date." + funcName + " = function(input){\n"
1252         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1253         + "var d = new Date();\n"
1254         + "y = d.getFullYear();\n"
1255         + "m = d.getMonth();\n"
1256         + "d = d.getDate();\n"
1257         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1258         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1259         + "if (results && results.length > 0) {";
1260     var regex = "";
1261
1262     var special = false;
1263     var ch = '';
1264     for (var i = 0; i < format.length; ++i) {
1265         ch = format.charAt(i);
1266         if (!special && ch == "\\") {
1267             special = true;
1268         }
1269         else if (special) {
1270             special = false;
1271             regex += String.escape(ch);
1272         }
1273         else {
1274             var obj = Date.formatCodeToRegex(ch, currentGroup);
1275             currentGroup += obj.g;
1276             regex += obj.s;
1277             if (obj.g && obj.c) {
1278                 code += obj.c;
1279             }
1280         }
1281     }
1282
1283     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1284         + "{v = new Date(y, m, d, h, i, s);}\n"
1285         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1286         + "{v = new Date(y, m, d, h, i);}\n"
1287         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1288         + "{v = new Date(y, m, d, h);}\n"
1289         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1290         + "{v = new Date(y, m, d);}\n"
1291         + "else if (y >= 0 && m >= 0)\n"
1292         + "{v = new Date(y, m);}\n"
1293         + "else if (y >= 0)\n"
1294         + "{v = new Date(y);}\n"
1295         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1296         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1297         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1298         + ";}";
1299
1300     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1301     /** eval:var:zzzzzzzzzzzzz */
1302     eval(code);
1303 };
1304
1305 // private
1306 Date.formatCodeToRegex = function(character, currentGroup) {
1307     switch (character) {
1308     case "D":
1309         return {g:0,
1310         c:null,
1311         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1312     case "j":
1313         return {g:1,
1314             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1315             s:"(\\d{1,2})"}; // day of month without leading zeroes
1316     case "d":
1317         return {g:1,
1318             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1319             s:"(\\d{2})"}; // day of month with leading zeroes
1320     case "l":
1321         return {g:0,
1322             c:null,
1323             s:"(?:" + Date.dayNames.join("|") + ")"};
1324     case "S":
1325         return {g:0,
1326             c:null,
1327             s:"(?:st|nd|rd|th)"};
1328     case "w":
1329         return {g:0,
1330             c:null,
1331             s:"\\d"};
1332     case "z":
1333         return {g:0,
1334             c:null,
1335             s:"(?:\\d{1,3})"};
1336     case "W":
1337         return {g:0,
1338             c:null,
1339             s:"(?:\\d{2})"};
1340     case "F":
1341         return {g:1,
1342             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1343             s:"(" + Date.monthNames.join("|") + ")"};
1344     case "M":
1345         return {g:1,
1346             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1347             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1348     case "n":
1349         return {g:1,
1350             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1351             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1352     case "m":
1353         return {g:1,
1354             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1355             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1356     case "t":
1357         return {g:0,
1358             c:null,
1359             s:"\\d{1,2}"};
1360     case "L":
1361         return {g:0,
1362             c:null,
1363             s:"(?:1|0)"};
1364     case "Y":
1365         return {g:1,
1366             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1367             s:"(\\d{4})"};
1368     case "y":
1369         return {g:1,
1370             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1371                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1372             s:"(\\d{1,2})"};
1373     case "a":
1374         return {g:1,
1375             c:"if (results[" + currentGroup + "] == 'am') {\n"
1376                 + "if (h == 12) { h = 0; }\n"
1377                 + "} else { if (h < 12) { h += 12; }}",
1378             s:"(am|pm)"};
1379     case "A":
1380         return {g:1,
1381             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1382                 + "if (h == 12) { h = 0; }\n"
1383                 + "} else { if (h < 12) { h += 12; }}",
1384             s:"(AM|PM)"};
1385     case "g":
1386     case "G":
1387         return {g:1,
1388             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1389             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1390     case "h":
1391     case "H":
1392         return {g:1,
1393             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1394             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1395     case "i":
1396         return {g:1,
1397             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1398             s:"(\\d{2})"};
1399     case "s":
1400         return {g:1,
1401             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1402             s:"(\\d{2})"};
1403     case "O":
1404         return {g:1,
1405             c:[
1406                 "o = results[", currentGroup, "];\n",
1407                 "var sn = o.substring(0,1);\n", // get + / - sign
1408                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1409                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1410                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1411                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1412             ].join(""),
1413             s:"([+\-]\\d{2,4})"};
1414     
1415     
1416     case "P":
1417         return {g:1,
1418                 c:[
1419                    "o = results[", currentGroup, "];\n",
1420                    "var sn = o.substring(0,1);\n",
1421                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1422                    "var mn = o.substring(4,6) % 60;\n",
1423                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1424                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1425             ].join(""),
1426             s:"([+\-]\\d{4})"};
1427     case "T":
1428         return {g:0,
1429             c:null,
1430             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1431     case "Z":
1432         return {g:1,
1433             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1434                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1435             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1436     default:
1437         return {g:0,
1438             c:null,
1439             s:String.escape(character)};
1440     }
1441 };
1442
1443 /**
1444  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1445  * @return {String} The abbreviated timezone name (e.g. 'CST')
1446  */
1447 Date.prototype.getTimezone = function() {
1448     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1449 };
1450
1451 /**
1452  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1453  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1454  */
1455 Date.prototype.getGMTOffset = function() {
1456     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1457         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1458         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1459 };
1460
1461 /**
1462  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1463  * @return {String} 2-characters representing hours and 2-characters representing minutes
1464  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1465  */
1466 Date.prototype.getGMTColonOffset = function() {
1467         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469                 + ":"
1470                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1471 }
1472
1473 /**
1474  * Get the numeric day number of the year, adjusted for leap year.
1475  * @return {Number} 0 through 364 (365 in leap years)
1476  */
1477 Date.prototype.getDayOfYear = function() {
1478     var num = 0;
1479     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1480     for (var i = 0; i < this.getMonth(); ++i) {
1481         num += Date.daysInMonth[i];
1482     }
1483     return num + this.getDate() - 1;
1484 };
1485
1486 /**
1487  * Get the string representation of the numeric week number of the year
1488  * (equivalent to the format specifier 'W').
1489  * @return {String} '00' through '52'
1490  */
1491 Date.prototype.getWeekOfYear = function() {
1492     // Skip to Thursday of this week
1493     var now = this.getDayOfYear() + (4 - this.getDay());
1494     // Find the first Thursday of the year
1495     var jan1 = new Date(this.getFullYear(), 0, 1);
1496     var then = (7 - jan1.getDay() + 4);
1497     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1498 };
1499
1500 /**
1501  * Whether or not the current date is in a leap year.
1502  * @return {Boolean} True if the current date is in a leap year, else false
1503  */
1504 Date.prototype.isLeapYear = function() {
1505     var year = this.getFullYear();
1506     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1507 };
1508
1509 /**
1510  * Get the first day of the current month, adjusted for leap year.  The returned value
1511  * is the numeric day index within the week (0-6) which can be used in conjunction with
1512  * the {@link #monthNames} array to retrieve the textual day name.
1513  * Example:
1514  *<pre><code>
1515 var dt = new Date('1/10/2007');
1516 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1517 </code></pre>
1518  * @return {Number} The day number (0-6)
1519  */
1520 Date.prototype.getFirstDayOfMonth = function() {
1521     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1522     return (day < 0) ? (day + 7) : day;
1523 };
1524
1525 /**
1526  * Get the last day of the current month, adjusted for leap year.  The returned value
1527  * is the numeric day index within the week (0-6) which can be used in conjunction with
1528  * the {@link #monthNames} array to retrieve the textual day name.
1529  * Example:
1530  *<pre><code>
1531 var dt = new Date('1/10/2007');
1532 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1533 </code></pre>
1534  * @return {Number} The day number (0-6)
1535  */
1536 Date.prototype.getLastDayOfMonth = function() {
1537     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1538     return (day < 0) ? (day + 7) : day;
1539 };
1540
1541
1542 /**
1543  * Get the first date of this date's month
1544  * @return {Date}
1545  */
1546 Date.prototype.getFirstDateOfMonth = function() {
1547     return new Date(this.getFullYear(), this.getMonth(), 1);
1548 };
1549
1550 /**
1551  * Get the last date of this date's month
1552  * @return {Date}
1553  */
1554 Date.prototype.getLastDateOfMonth = function() {
1555     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1556 };
1557 /**
1558  * Get the number of days in the current month, adjusted for leap year.
1559  * @return {Number} The number of days in the month
1560  */
1561 Date.prototype.getDaysInMonth = function() {
1562     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1563     return Date.daysInMonth[this.getMonth()];
1564 };
1565
1566 /**
1567  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1568  * @return {String} 'st, 'nd', 'rd' or 'th'
1569  */
1570 Date.prototype.getSuffix = function() {
1571     switch (this.getDate()) {
1572         case 1:
1573         case 21:
1574         case 31:
1575             return "st";
1576         case 2:
1577         case 22:
1578             return "nd";
1579         case 3:
1580         case 23:
1581             return "rd";
1582         default:
1583             return "th";
1584     }
1585 };
1586
1587 // private
1588 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1589
1590 /**
1591  * An array of textual month names.
1592  * Override these values for international dates, for example...
1593  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1594  * @type Array
1595  * @static
1596  */
1597 Date.monthNames =
1598    ["January",
1599     "February",
1600     "March",
1601     "April",
1602     "May",
1603     "June",
1604     "July",
1605     "August",
1606     "September",
1607     "October",
1608     "November",
1609     "December"];
1610
1611 /**
1612  * An array of textual day names.
1613  * Override these values for international dates, for example...
1614  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1615  * @type Array
1616  * @static
1617  */
1618 Date.dayNames =
1619    ["Sunday",
1620     "Monday",
1621     "Tuesday",
1622     "Wednesday",
1623     "Thursday",
1624     "Friday",
1625     "Saturday"];
1626
1627 // private
1628 Date.y2kYear = 50;
1629 // private
1630 Date.monthNumbers = {
1631     Jan:0,
1632     Feb:1,
1633     Mar:2,
1634     Apr:3,
1635     May:4,
1636     Jun:5,
1637     Jul:6,
1638     Aug:7,
1639     Sep:8,
1640     Oct:9,
1641     Nov:10,
1642     Dec:11};
1643
1644 /**
1645  * Creates and returns a new Date instance with the exact same date value as the called instance.
1646  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1647  * variable will also be changed.  When the intention is to create a new variable that will not
1648  * modify the original instance, you should create a clone.
1649  *
1650  * Example of correctly cloning a date:
1651  * <pre><code>
1652 //wrong way:
1653 var orig = new Date('10/1/2006');
1654 var copy = orig;
1655 copy.setDate(5);
1656 document.write(orig);  //returns 'Thu Oct 05 2006'!
1657
1658 //correct way:
1659 var orig = new Date('10/1/2006');
1660 var copy = orig.clone();
1661 copy.setDate(5);
1662 document.write(orig);  //returns 'Thu Oct 01 2006'
1663 </code></pre>
1664  * @return {Date} The new Date instance
1665  */
1666 Date.prototype.clone = function() {
1667         return new Date(this.getTime());
1668 };
1669
1670 /**
1671  * Clears any time information from this date
1672  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1673  @return {Date} this or the clone
1674  */
1675 Date.prototype.clearTime = function(clone){
1676     if(clone){
1677         return this.clone().clearTime();
1678     }
1679     this.setHours(0);
1680     this.setMinutes(0);
1681     this.setSeconds(0);
1682     this.setMilliseconds(0);
1683     return this;
1684 };
1685
1686 // private
1687 // safari setMonth is broken
1688 if(Roo.isSafari){
1689     Date.brokenSetMonth = Date.prototype.setMonth;
1690         Date.prototype.setMonth = function(num){
1691                 if(num <= -1){
1692                         var n = Math.ceil(-num);
1693                         var back_year = Math.ceil(n/12);
1694                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1695                         this.setFullYear(this.getFullYear() - back_year);
1696                         return Date.brokenSetMonth.call(this, month);
1697                 } else {
1698                         return Date.brokenSetMonth.apply(this, arguments);
1699                 }
1700         };
1701 }
1702
1703 /** Date interval constant 
1704 * @static 
1705 * @type String */
1706 Date.MILLI = "ms";
1707 /** Date interval constant 
1708 * @static 
1709 * @type String */
1710 Date.SECOND = "s";
1711 /** Date interval constant 
1712 * @static 
1713 * @type String */
1714 Date.MINUTE = "mi";
1715 /** Date interval constant 
1716 * @static 
1717 * @type String */
1718 Date.HOUR = "h";
1719 /** Date interval constant 
1720 * @static 
1721 * @type String */
1722 Date.DAY = "d";
1723 /** Date interval constant 
1724 * @static 
1725 * @type String */
1726 Date.MONTH = "mo";
1727 /** Date interval constant 
1728 * @static 
1729 * @type String */
1730 Date.YEAR = "y";
1731
1732 /**
1733  * Provides a convenient method of performing basic date arithmetic.  This method
1734  * does not modify the Date instance being called - it creates and returns
1735  * a new Date instance containing the resulting date value.
1736  *
1737  * Examples:
1738  * <pre><code>
1739 //Basic usage:
1740 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1741 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1742
1743 //Negative values will subtract correctly:
1744 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1745 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1746
1747 //You can even chain several calls together in one line!
1748 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1749 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1750  </code></pre>
1751  *
1752  * @param {String} interval   A valid date interval enum value
1753  * @param {Number} value      The amount to add to the current date
1754  * @return {Date} The new Date instance
1755  */
1756 Date.prototype.add = function(interval, value){
1757   var d = this.clone();
1758   if (!interval || value === 0) return d;
1759   switch(interval.toLowerCase()){
1760     case Date.MILLI:
1761       d.setMilliseconds(this.getMilliseconds() + value);
1762       break;
1763     case Date.SECOND:
1764       d.setSeconds(this.getSeconds() + value);
1765       break;
1766     case Date.MINUTE:
1767       d.setMinutes(this.getMinutes() + value);
1768       break;
1769     case Date.HOUR:
1770       d.setHours(this.getHours() + value);
1771       break;
1772     case Date.DAY:
1773       d.setDate(this.getDate() + value);
1774       break;
1775     case Date.MONTH:
1776       var day = this.getDate();
1777       if(day > 28){
1778           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1779       }
1780       d.setDate(day);
1781       d.setMonth(this.getMonth() + value);
1782       break;
1783     case Date.YEAR:
1784       d.setFullYear(this.getFullYear() + value);
1785       break;
1786   }
1787   return d;
1788 };
1789 /*
1790  * Based on:
1791  * Ext JS Library 1.1.1
1792  * Copyright(c) 2006-2007, Ext JS, LLC.
1793  *
1794  * Originally Released Under LGPL - original licence link has changed is not relivant.
1795  *
1796  * Fork - LGPL
1797  * <script type="text/javascript">
1798  */
1799
1800 /**
1801  * @class Roo.lib.Dom
1802  * @static
1803  * 
1804  * Dom utils (from YIU afaik)
1805  * 
1806  **/
1807 Roo.lib.Dom = {
1808     /**
1809      * Get the view width
1810      * @param {Boolean} full True will get the full document, otherwise it's the view width
1811      * @return {Number} The width
1812      */
1813      
1814     getViewWidth : function(full) {
1815         return full ? this.getDocumentWidth() : this.getViewportWidth();
1816     },
1817     /**
1818      * Get the view height
1819      * @param {Boolean} full True will get the full document, otherwise it's the view height
1820      * @return {Number} The height
1821      */
1822     getViewHeight : function(full) {
1823         return full ? this.getDocumentHeight() : this.getViewportHeight();
1824     },
1825
1826     getDocumentHeight: function() {
1827         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1828         return Math.max(scrollHeight, this.getViewportHeight());
1829     },
1830
1831     getDocumentWidth: function() {
1832         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1833         return Math.max(scrollWidth, this.getViewportWidth());
1834     },
1835
1836     getViewportHeight: function() {
1837         var height = self.innerHeight;
1838         var mode = document.compatMode;
1839
1840         if ((mode || Roo.isIE) && !Roo.isOpera) {
1841             height = (mode == "CSS1Compat") ?
1842                      document.documentElement.clientHeight :
1843                      document.body.clientHeight;
1844         }
1845
1846         return height;
1847     },
1848
1849     getViewportWidth: function() {
1850         var width = self.innerWidth;
1851         var mode = document.compatMode;
1852
1853         if (mode || Roo.isIE) {
1854             width = (mode == "CSS1Compat") ?
1855                     document.documentElement.clientWidth :
1856                     document.body.clientWidth;
1857         }
1858         return width;
1859     },
1860
1861     isAncestor : function(p, c) {
1862         p = Roo.getDom(p);
1863         c = Roo.getDom(c);
1864         if (!p || !c) {
1865             return false;
1866         }
1867
1868         if (p.contains && !Roo.isSafari) {
1869             return p.contains(c);
1870         } else if (p.compareDocumentPosition) {
1871             return !!(p.compareDocumentPosition(c) & 16);
1872         } else {
1873             var parent = c.parentNode;
1874             while (parent) {
1875                 if (parent == p) {
1876                     return true;
1877                 }
1878                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1879                     return false;
1880                 }
1881                 parent = parent.parentNode;
1882             }
1883             return false;
1884         }
1885     },
1886
1887     getRegion : function(el) {
1888         return Roo.lib.Region.getRegion(el);
1889     },
1890
1891     getY : function(el) {
1892         return this.getXY(el)[1];
1893     },
1894
1895     getX : function(el) {
1896         return this.getXY(el)[0];
1897     },
1898
1899     getXY : function(el) {
1900         var p, pe, b, scroll, bd = document.body;
1901         el = Roo.getDom(el);
1902         var fly = Roo.lib.AnimBase.fly;
1903         if (el.getBoundingClientRect) {
1904             b = el.getBoundingClientRect();
1905             scroll = fly(document).getScroll();
1906             return [b.left + scroll.left, b.top + scroll.top];
1907         }
1908         var x = 0, y = 0;
1909
1910         p = el;
1911
1912         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1913
1914         while (p) {
1915
1916             x += p.offsetLeft;
1917             y += p.offsetTop;
1918
1919             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1920                 hasAbsolute = true;
1921             }
1922
1923             if (Roo.isGecko) {
1924                 pe = fly(p);
1925
1926                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1927                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1928
1929
1930                 x += bl;
1931                 y += bt;
1932
1933
1934                 if (p != el && pe.getStyle('overflow') != 'visible') {
1935                     x += bl;
1936                     y += bt;
1937                 }
1938             }
1939             p = p.offsetParent;
1940         }
1941
1942         if (Roo.isSafari && hasAbsolute) {
1943             x -= bd.offsetLeft;
1944             y -= bd.offsetTop;
1945         }
1946
1947         if (Roo.isGecko && !hasAbsolute) {
1948             var dbd = fly(bd);
1949             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1950             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1951         }
1952
1953         p = el.parentNode;
1954         while (p && p != bd) {
1955             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1956                 x -= p.scrollLeft;
1957                 y -= p.scrollTop;
1958             }
1959             p = p.parentNode;
1960         }
1961         return [x, y];
1962     },
1963  
1964   
1965
1966
1967     setXY : function(el, xy) {
1968         el = Roo.fly(el, '_setXY');
1969         el.position();
1970         var pts = el.translatePoints(xy);
1971         if (xy[0] !== false) {
1972             el.dom.style.left = pts.left + "px";
1973         }
1974         if (xy[1] !== false) {
1975             el.dom.style.top = pts.top + "px";
1976         }
1977     },
1978
1979     setX : function(el, x) {
1980         this.setXY(el, [x, false]);
1981     },
1982
1983     setY : function(el, y) {
1984         this.setXY(el, [false, y]);
1985     }
1986 };
1987 /*
1988  * Portions of this file are based on pieces of Yahoo User Interface Library
1989  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1990  * YUI licensed under the BSD License:
1991  * http://developer.yahoo.net/yui/license.txt
1992  * <script type="text/javascript">
1993  *
1994  */
1995
1996 Roo.lib.Event = function() {
1997     var loadComplete = false;
1998     var listeners = [];
1999     var unloadListeners = [];
2000     var retryCount = 0;
2001     var onAvailStack = [];
2002     var counter = 0;
2003     var lastError = null;
2004
2005     return {
2006         POLL_RETRYS: 200,
2007         POLL_INTERVAL: 20,
2008         EL: 0,
2009         TYPE: 1,
2010         FN: 2,
2011         WFN: 3,
2012         OBJ: 3,
2013         ADJ_SCOPE: 4,
2014         _interval: null,
2015
2016         startInterval: function() {
2017             if (!this._interval) {
2018                 var self = this;
2019                 var callback = function() {
2020                     self._tryPreloadAttach();
2021                 };
2022                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2023
2024             }
2025         },
2026
2027         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2028             onAvailStack.push({ id:         p_id,
2029                 fn:         p_fn,
2030                 obj:        p_obj,
2031                 override:   p_override,
2032                 checkReady: false    });
2033
2034             retryCount = this.POLL_RETRYS;
2035             this.startInterval();
2036         },
2037
2038
2039         addListener: function(el, eventName, fn) {
2040             el = Roo.getDom(el);
2041             if (!el || !fn) {
2042                 return false;
2043             }
2044
2045             if ("unload" == eventName) {
2046                 unloadListeners[unloadListeners.length] =
2047                 [el, eventName, fn];
2048                 return true;
2049             }
2050
2051             var wrappedFn = function(e) {
2052                 return fn(Roo.lib.Event.getEvent(e));
2053             };
2054
2055             var li = [el, eventName, fn, wrappedFn];
2056
2057             var index = listeners.length;
2058             listeners[index] = li;
2059
2060             this.doAdd(el, eventName, wrappedFn, false);
2061             return true;
2062
2063         },
2064
2065
2066         removeListener: function(el, eventName, fn) {
2067             var i, len;
2068
2069             el = Roo.getDom(el);
2070
2071             if(!fn) {
2072                 return this.purgeElement(el, false, eventName);
2073             }
2074
2075
2076             if ("unload" == eventName) {
2077
2078                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2079                     var li = unloadListeners[i];
2080                     if (li &&
2081                         li[0] == el &&
2082                         li[1] == eventName &&
2083                         li[2] == fn) {
2084                         unloadListeners.splice(i, 1);
2085                         return true;
2086                     }
2087                 }
2088
2089                 return false;
2090             }
2091
2092             var cacheItem = null;
2093
2094
2095             var index = arguments[3];
2096
2097             if ("undefined" == typeof index) {
2098                 index = this._getCacheIndex(el, eventName, fn);
2099             }
2100
2101             if (index >= 0) {
2102                 cacheItem = listeners[index];
2103             }
2104
2105             if (!el || !cacheItem) {
2106                 return false;
2107             }
2108
2109             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2110
2111             delete listeners[index][this.WFN];
2112             delete listeners[index][this.FN];
2113             listeners.splice(index, 1);
2114
2115             return true;
2116
2117         },
2118
2119
2120         getTarget: function(ev, resolveTextNode) {
2121             ev = ev.browserEvent || ev;
2122             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2123             var t = ev.target || ev.srcElement;
2124             return this.resolveTextNode(t);
2125         },
2126
2127
2128         resolveTextNode: function(node) {
2129             if (Roo.isSafari && node && 3 == node.nodeType) {
2130                 return node.parentNode;
2131             } else {
2132                 return node;
2133             }
2134         },
2135
2136
2137         getPageX: function(ev) {
2138             ev = ev.browserEvent || ev;
2139             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2140             var x = ev.pageX;
2141             if (!x && 0 !== x) {
2142                 x = ev.clientX || 0;
2143
2144                 if (Roo.isIE) {
2145                     x += this.getScroll()[1];
2146                 }
2147             }
2148
2149             return x;
2150         },
2151
2152
2153         getPageY: function(ev) {
2154             ev = ev.browserEvent || ev;
2155             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2156             var y = ev.pageY;
2157             if (!y && 0 !== y) {
2158                 y = ev.clientY || 0;
2159
2160                 if (Roo.isIE) {
2161                     y += this.getScroll()[0];
2162                 }
2163             }
2164
2165
2166             return y;
2167         },
2168
2169
2170         getXY: function(ev) {
2171             ev = ev.browserEvent || ev;
2172             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2173             return [this.getPageX(ev), this.getPageY(ev)];
2174         },
2175
2176
2177         getRelatedTarget: function(ev) {
2178             ev = ev.browserEvent || ev;
2179             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2180             var t = ev.relatedTarget;
2181             if (!t) {
2182                 if (ev.type == "mouseout") {
2183                     t = ev.toElement;
2184                 } else if (ev.type == "mouseover") {
2185                     t = ev.fromElement;
2186                 }
2187             }
2188
2189             return this.resolveTextNode(t);
2190         },
2191
2192
2193         getTime: function(ev) {
2194             ev = ev.browserEvent || ev;
2195             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2196             if (!ev.time) {
2197                 var t = new Date().getTime();
2198                 try {
2199                     ev.time = t;
2200                 } catch(ex) {
2201                     this.lastError = ex;
2202                     return t;
2203                 }
2204             }
2205
2206             return ev.time;
2207         },
2208
2209
2210         stopEvent: function(ev) {
2211             this.stopPropagation(ev);
2212             this.preventDefault(ev);
2213         },
2214
2215
2216         stopPropagation: function(ev) {
2217             ev = ev.browserEvent || ev;
2218             if (ev.stopPropagation) {
2219                 ev.stopPropagation();
2220             } else {
2221                 ev.cancelBubble = true;
2222             }
2223         },
2224
2225
2226         preventDefault: function(ev) {
2227             ev = ev.browserEvent || ev;
2228             if(ev.preventDefault) {
2229                 ev.preventDefault();
2230             } else {
2231                 ev.returnValue = false;
2232             }
2233         },
2234
2235
2236         getEvent: function(e) {
2237             var ev = e || window.event;
2238             if (!ev) {
2239                 var c = this.getEvent.caller;
2240                 while (c) {
2241                     ev = c.arguments[0];
2242                     if (ev && Event == ev.constructor) {
2243                         break;
2244                     }
2245                     c = c.caller;
2246                 }
2247             }
2248             return ev;
2249         },
2250
2251
2252         getCharCode: function(ev) {
2253             ev = ev.browserEvent || ev;
2254             return ev.charCode || ev.keyCode || 0;
2255         },
2256
2257
2258         _getCacheIndex: function(el, eventName, fn) {
2259             for (var i = 0,len = listeners.length; i < len; ++i) {
2260                 var li = listeners[i];
2261                 if (li &&
2262                     li[this.FN] == fn &&
2263                     li[this.EL] == el &&
2264                     li[this.TYPE] == eventName) {
2265                     return i;
2266                 }
2267             }
2268
2269             return -1;
2270         },
2271
2272
2273         elCache: {},
2274
2275
2276         getEl: function(id) {
2277             return document.getElementById(id);
2278         },
2279
2280
2281         clearCache: function() {
2282         },
2283
2284
2285         _load: function(e) {
2286             loadComplete = true;
2287             var EU = Roo.lib.Event;
2288
2289
2290             if (Roo.isIE) {
2291                 EU.doRemove(window, "load", EU._load);
2292             }
2293         },
2294
2295
2296         _tryPreloadAttach: function() {
2297
2298             if (this.locked) {
2299                 return false;
2300             }
2301
2302             this.locked = true;
2303
2304
2305             var tryAgain = !loadComplete;
2306             if (!tryAgain) {
2307                 tryAgain = (retryCount > 0);
2308             }
2309
2310
2311             var notAvail = [];
2312             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2313                 var item = onAvailStack[i];
2314                 if (item) {
2315                     var el = this.getEl(item.id);
2316
2317                     if (el) {
2318                         if (!item.checkReady ||
2319                             loadComplete ||
2320                             el.nextSibling ||
2321                             (document && document.body)) {
2322
2323                             var scope = el;
2324                             if (item.override) {
2325                                 if (item.override === true) {
2326                                     scope = item.obj;
2327                                 } else {
2328                                     scope = item.override;
2329                                 }
2330                             }
2331                             item.fn.call(scope, item.obj);
2332                             onAvailStack[i] = null;
2333                         }
2334                     } else {
2335                         notAvail.push(item);
2336                     }
2337                 }
2338             }
2339
2340             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2341
2342             if (tryAgain) {
2343
2344                 this.startInterval();
2345             } else {
2346                 clearInterval(this._interval);
2347                 this._interval = null;
2348             }
2349
2350             this.locked = false;
2351
2352             return true;
2353
2354         },
2355
2356
2357         purgeElement: function(el, recurse, eventName) {
2358             var elListeners = this.getListeners(el, eventName);
2359             if (elListeners) {
2360                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2361                     var l = elListeners[i];
2362                     this.removeListener(el, l.type, l.fn);
2363                 }
2364             }
2365
2366             if (recurse && el && el.childNodes) {
2367                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2368                     this.purgeElement(el.childNodes[i], recurse, eventName);
2369                 }
2370             }
2371         },
2372
2373
2374         getListeners: function(el, eventName) {
2375             var results = [], searchLists;
2376             if (!eventName) {
2377                 searchLists = [listeners, unloadListeners];
2378             } else if (eventName == "unload") {
2379                 searchLists = [unloadListeners];
2380             } else {
2381                 searchLists = [listeners];
2382             }
2383
2384             for (var j = 0; j < searchLists.length; ++j) {
2385                 var searchList = searchLists[j];
2386                 if (searchList && searchList.length > 0) {
2387                     for (var i = 0,len = searchList.length; i < len; ++i) {
2388                         var l = searchList[i];
2389                         if (l && l[this.EL] === el &&
2390                             (!eventName || eventName === l[this.TYPE])) {
2391                             results.push({
2392                                 type:   l[this.TYPE],
2393                                 fn:     l[this.FN],
2394                                 obj:    l[this.OBJ],
2395                                 adjust: l[this.ADJ_SCOPE],
2396                                 index:  i
2397                             });
2398                         }
2399                     }
2400                 }
2401             }
2402
2403             return (results.length) ? results : null;
2404         },
2405
2406
2407         _unload: function(e) {
2408
2409             var EU = Roo.lib.Event, i, j, l, len, index;
2410
2411             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2412                 l = unloadListeners[i];
2413                 if (l) {
2414                     var scope = window;
2415                     if (l[EU.ADJ_SCOPE]) {
2416                         if (l[EU.ADJ_SCOPE] === true) {
2417                             scope = l[EU.OBJ];
2418                         } else {
2419                             scope = l[EU.ADJ_SCOPE];
2420                         }
2421                     }
2422                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2423                     unloadListeners[i] = null;
2424                     l = null;
2425                     scope = null;
2426                 }
2427             }
2428
2429             unloadListeners = null;
2430
2431             if (listeners && listeners.length > 0) {
2432                 j = listeners.length;
2433                 while (j) {
2434                     index = j - 1;
2435                     l = listeners[index];
2436                     if (l) {
2437                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2438                                 l[EU.FN], index);
2439                     }
2440                     j = j - 1;
2441                 }
2442                 l = null;
2443
2444                 EU.clearCache();
2445             }
2446
2447             EU.doRemove(window, "unload", EU._unload);
2448
2449         },
2450
2451
2452         getScroll: function() {
2453             var dd = document.documentElement, db = document.body;
2454             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2455                 return [dd.scrollTop, dd.scrollLeft];
2456             } else if (db) {
2457                 return [db.scrollTop, db.scrollLeft];
2458             } else {
2459                 return [0, 0];
2460             }
2461         },
2462
2463
2464         doAdd: function () {
2465             if (window.addEventListener) {
2466                 return function(el, eventName, fn, capture) {
2467                     el.addEventListener(eventName, fn, (capture));
2468                 };
2469             } else if (window.attachEvent) {
2470                 return function(el, eventName, fn, capture) {
2471                     el.attachEvent("on" + eventName, fn);
2472                 };
2473             } else {
2474                 return function() {
2475                 };
2476             }
2477         }(),
2478
2479
2480         doRemove: function() {
2481             if (window.removeEventListener) {
2482                 return function (el, eventName, fn, capture) {
2483                     el.removeEventListener(eventName, fn, (capture));
2484                 };
2485             } else if (window.detachEvent) {
2486                 return function (el, eventName, fn) {
2487                     el.detachEvent("on" + eventName, fn);
2488                 };
2489             } else {
2490                 return function() {
2491                 };
2492             }
2493         }()
2494     };
2495     
2496 }();
2497 (function() {     
2498    
2499     var E = Roo.lib.Event;
2500     E.on = E.addListener;
2501     E.un = E.removeListener;
2502
2503     if (document && document.body) {
2504         E._load();
2505     } else {
2506         E.doAdd(window, "load", E._load);
2507     }
2508     E.doAdd(window, "unload", E._unload);
2509     E._tryPreloadAttach();
2510 })();
2511
2512 /*
2513  * Portions of this file are based on pieces of Yahoo User Interface Library
2514  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2515  * YUI licensed under the BSD License:
2516  * http://developer.yahoo.net/yui/license.txt
2517  * <script type="text/javascript">
2518  *
2519  */
2520
2521 (function() {
2522     /**
2523      * @class Roo.lib.Ajax
2524      *
2525      */
2526     Roo.lib.Ajax = {
2527         /**
2528          * @static 
2529          */
2530         request : function(method, uri, cb, data, options) {
2531             if(options){
2532                 var hs = options.headers;
2533                 if(hs){
2534                     for(var h in hs){
2535                         if(hs.hasOwnProperty(h)){
2536                             this.initHeader(h, hs[h], false);
2537                         }
2538                     }
2539                 }
2540                 if(options.xmlData){
2541                     this.initHeader('Content-Type', 'text/xml', false);
2542                     method = 'POST';
2543                     data = options.xmlData;
2544                 }
2545             }
2546
2547             return this.asyncRequest(method, uri, cb, data);
2548         },
2549
2550         serializeForm : function(form) {
2551             if(typeof form == 'string') {
2552                 form = (document.getElementById(form) || document.forms[form]);
2553             }
2554
2555             var el, name, val, disabled, data = '', hasSubmit = false;
2556             for (var i = 0; i < form.elements.length; i++) {
2557                 el = form.elements[i];
2558                 disabled = form.elements[i].disabled;
2559                 name = form.elements[i].name;
2560                 val = form.elements[i].value;
2561
2562                 if (!disabled && name){
2563                     switch (el.type)
2564                             {
2565                         case 'select-one':
2566                         case 'select-multiple':
2567                             for (var j = 0; j < el.options.length; j++) {
2568                                 if (el.options[j].selected) {
2569                                     if (Roo.isIE) {
2570                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2571                                     }
2572                                     else {
2573                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2574                                     }
2575                                 }
2576                             }
2577                             break;
2578                         case 'radio':
2579                         case 'checkbox':
2580                             if (el.checked) {
2581                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2582                             }
2583                             break;
2584                         case 'file':
2585
2586                         case undefined:
2587
2588                         case 'reset':
2589
2590                         case 'button':
2591
2592                             break;
2593                         case 'submit':
2594                             if(hasSubmit == false) {
2595                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596                                 hasSubmit = true;
2597                             }
2598                             break;
2599                         default:
2600                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2601                             break;
2602                     }
2603                 }
2604             }
2605             data = data.substr(0, data.length - 1);
2606             return data;
2607         },
2608
2609         headers:{},
2610
2611         hasHeaders:false,
2612
2613         useDefaultHeader:true,
2614
2615         defaultPostHeader:'application/x-www-form-urlencoded',
2616
2617         useDefaultXhrHeader:true,
2618
2619         defaultXhrHeader:'XMLHttpRequest',
2620
2621         hasDefaultHeaders:true,
2622
2623         defaultHeaders:{},
2624
2625         poll:{},
2626
2627         timeout:{},
2628
2629         pollInterval:50,
2630
2631         transactionId:0,
2632
2633         setProgId:function(id)
2634         {
2635             this.activeX.unshift(id);
2636         },
2637
2638         setDefaultPostHeader:function(b)
2639         {
2640             this.useDefaultHeader = b;
2641         },
2642
2643         setDefaultXhrHeader:function(b)
2644         {
2645             this.useDefaultXhrHeader = b;
2646         },
2647
2648         setPollingInterval:function(i)
2649         {
2650             if (typeof i == 'number' && isFinite(i)) {
2651                 this.pollInterval = i;
2652             }
2653         },
2654
2655         createXhrObject:function(transactionId)
2656         {
2657             var obj,http;
2658             try
2659             {
2660
2661                 http = new XMLHttpRequest();
2662
2663                 obj = { conn:http, tId:transactionId };
2664             }
2665             catch(e)
2666             {
2667                 for (var i = 0; i < this.activeX.length; ++i) {
2668                     try
2669                     {
2670
2671                         http = new ActiveXObject(this.activeX[i]);
2672
2673                         obj = { conn:http, tId:transactionId };
2674                         break;
2675                     }
2676                     catch(e) {
2677                     }
2678                 }
2679             }
2680             finally
2681             {
2682                 return obj;
2683             }
2684         },
2685
2686         getConnectionObject:function()
2687         {
2688             var o;
2689             var tId = this.transactionId;
2690
2691             try
2692             {
2693                 o = this.createXhrObject(tId);
2694                 if (o) {
2695                     this.transactionId++;
2696                 }
2697             }
2698             catch(e) {
2699             }
2700             finally
2701             {
2702                 return o;
2703             }
2704         },
2705
2706         asyncRequest:function(method, uri, callback, postData)
2707         {
2708             var o = this.getConnectionObject();
2709
2710             if (!o) {
2711                 return null;
2712             }
2713             else {
2714                 o.conn.open(method, uri, true);
2715
2716                 if (this.useDefaultXhrHeader) {
2717                     if (!this.defaultHeaders['X-Requested-With']) {
2718                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2719                     }
2720                 }
2721
2722                 if(postData && this.useDefaultHeader){
2723                     this.initHeader('Content-Type', this.defaultPostHeader);
2724                 }
2725
2726                  if (this.hasDefaultHeaders || this.hasHeaders) {
2727                     this.setHeader(o);
2728                 }
2729
2730                 this.handleReadyState(o, callback);
2731                 o.conn.send(postData || null);
2732
2733                 return o;
2734             }
2735         },
2736
2737         handleReadyState:function(o, callback)
2738         {
2739             var oConn = this;
2740
2741             if (callback && callback.timeout) {
2742                 
2743                 this.timeout[o.tId] = window.setTimeout(function() {
2744                     oConn.abort(o, callback, true);
2745                 }, callback.timeout);
2746             }
2747
2748             this.poll[o.tId] = window.setInterval(
2749                     function() {
2750                         if (o.conn && o.conn.readyState == 4) {
2751                             window.clearInterval(oConn.poll[o.tId]);
2752                             delete oConn.poll[o.tId];
2753
2754                             if(callback && callback.timeout) {
2755                                 window.clearTimeout(oConn.timeout[o.tId]);
2756                                 delete oConn.timeout[o.tId];
2757                             }
2758
2759                             oConn.handleTransactionResponse(o, callback);
2760                         }
2761                     }
2762                     , this.pollInterval);
2763         },
2764
2765         handleTransactionResponse:function(o, callback, isAbort)
2766         {
2767
2768             if (!callback) {
2769                 this.releaseObject(o);
2770                 return;
2771             }
2772
2773             var httpStatus, responseObject;
2774
2775             try
2776             {
2777                 if (o.conn.status !== undefined && o.conn.status != 0) {
2778                     httpStatus = o.conn.status;
2779                 }
2780                 else {
2781                     httpStatus = 13030;
2782                 }
2783             }
2784             catch(e) {
2785
2786
2787                 httpStatus = 13030;
2788             }
2789
2790             if (httpStatus >= 200 && httpStatus < 300) {
2791                 responseObject = this.createResponseObject(o, callback.argument);
2792                 if (callback.success) {
2793                     if (!callback.scope) {
2794                         callback.success(responseObject);
2795                     }
2796                     else {
2797
2798
2799                         callback.success.apply(callback.scope, [responseObject]);
2800                     }
2801                 }
2802             }
2803             else {
2804                 switch (httpStatus) {
2805
2806                     case 12002:
2807                     case 12029:
2808                     case 12030:
2809                     case 12031:
2810                     case 12152:
2811                     case 13030:
2812                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2813                         if (callback.failure) {
2814                             if (!callback.scope) {
2815                                 callback.failure(responseObject);
2816                             }
2817                             else {
2818                                 callback.failure.apply(callback.scope, [responseObject]);
2819                             }
2820                         }
2821                         break;
2822                     default:
2823                         responseObject = this.createResponseObject(o, callback.argument);
2824                         if (callback.failure) {
2825                             if (!callback.scope) {
2826                                 callback.failure(responseObject);
2827                             }
2828                             else {
2829                                 callback.failure.apply(callback.scope, [responseObject]);
2830                             }
2831                         }
2832                 }
2833             }
2834
2835             this.releaseObject(o);
2836             responseObject = null;
2837         },
2838
2839         createResponseObject:function(o, callbackArg)
2840         {
2841             var obj = {};
2842             var headerObj = {};
2843
2844             try
2845             {
2846                 var headerStr = o.conn.getAllResponseHeaders();
2847                 var header = headerStr.split('\n');
2848                 for (var i = 0; i < header.length; i++) {
2849                     var delimitPos = header[i].indexOf(':');
2850                     if (delimitPos != -1) {
2851                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2852                     }
2853                 }
2854             }
2855             catch(e) {
2856             }
2857
2858             obj.tId = o.tId;
2859             obj.status = o.conn.status;
2860             obj.statusText = o.conn.statusText;
2861             obj.getResponseHeader = headerObj;
2862             obj.getAllResponseHeaders = headerStr;
2863             obj.responseText = o.conn.responseText;
2864             obj.responseXML = o.conn.responseXML;
2865
2866             if (typeof callbackArg !== undefined) {
2867                 obj.argument = callbackArg;
2868             }
2869
2870             return obj;
2871         },
2872
2873         createExceptionObject:function(tId, callbackArg, isAbort)
2874         {
2875             var COMM_CODE = 0;
2876             var COMM_ERROR = 'communication failure';
2877             var ABORT_CODE = -1;
2878             var ABORT_ERROR = 'transaction aborted';
2879
2880             var obj = {};
2881
2882             obj.tId = tId;
2883             if (isAbort) {
2884                 obj.status = ABORT_CODE;
2885                 obj.statusText = ABORT_ERROR;
2886             }
2887             else {
2888                 obj.status = COMM_CODE;
2889                 obj.statusText = COMM_ERROR;
2890             }
2891
2892             if (callbackArg) {
2893                 obj.argument = callbackArg;
2894             }
2895
2896             return obj;
2897         },
2898
2899         initHeader:function(label, value, isDefault)
2900         {
2901             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2902
2903             if (headerObj[label] === undefined) {
2904                 headerObj[label] = value;
2905             }
2906             else {
2907
2908
2909                 headerObj[label] = value + "," + headerObj[label];
2910             }
2911
2912             if (isDefault) {
2913                 this.hasDefaultHeaders = true;
2914             }
2915             else {
2916                 this.hasHeaders = true;
2917             }
2918         },
2919
2920
2921         setHeader:function(o)
2922         {
2923             if (this.hasDefaultHeaders) {
2924                 for (var prop in this.defaultHeaders) {
2925                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2926                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2927                     }
2928                 }
2929             }
2930
2931             if (this.hasHeaders) {
2932                 for (var prop in this.headers) {
2933                     if (this.headers.hasOwnProperty(prop)) {
2934                         o.conn.setRequestHeader(prop, this.headers[prop]);
2935                     }
2936                 }
2937                 this.headers = {};
2938                 this.hasHeaders = false;
2939             }
2940         },
2941
2942         resetDefaultHeaders:function() {
2943             delete this.defaultHeaders;
2944             this.defaultHeaders = {};
2945             this.hasDefaultHeaders = false;
2946         },
2947
2948         abort:function(o, callback, isTimeout)
2949         {
2950             if(this.isCallInProgress(o)) {
2951                 o.conn.abort();
2952                 window.clearInterval(this.poll[o.tId]);
2953                 delete this.poll[o.tId];
2954                 if (isTimeout) {
2955                     delete this.timeout[o.tId];
2956                 }
2957
2958                 this.handleTransactionResponse(o, callback, true);
2959
2960                 return true;
2961             }
2962             else {
2963                 return false;
2964             }
2965         },
2966
2967
2968         isCallInProgress:function(o)
2969         {
2970             if (o && o.conn) {
2971                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2972             }
2973             else {
2974
2975                 return false;
2976             }
2977         },
2978
2979
2980         releaseObject:function(o)
2981         {
2982
2983             o.conn = null;
2984
2985             o = null;
2986         },
2987
2988         activeX:[
2989         'MSXML2.XMLHTTP.3.0',
2990         'MSXML2.XMLHTTP',
2991         'Microsoft.XMLHTTP'
2992         ]
2993
2994
2995     };
2996 })();/*
2997  * Portions of this file are based on pieces of Yahoo User Interface Library
2998  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2999  * YUI licensed under the BSD License:
3000  * http://developer.yahoo.net/yui/license.txt
3001  * <script type="text/javascript">
3002  *
3003  */
3004
3005 Roo.lib.Region = function(t, r, b, l) {
3006     this.top = t;
3007     this[1] = t;
3008     this.right = r;
3009     this.bottom = b;
3010     this.left = l;
3011     this[0] = l;
3012 };
3013
3014
3015 Roo.lib.Region.prototype = {
3016     contains : function(region) {
3017         return ( region.left >= this.left &&
3018                  region.right <= this.right &&
3019                  region.top >= this.top &&
3020                  region.bottom <= this.bottom    );
3021
3022     },
3023
3024     getArea : function() {
3025         return ( (this.bottom - this.top) * (this.right - this.left) );
3026     },
3027
3028     intersect : function(region) {
3029         var t = Math.max(this.top, region.top);
3030         var r = Math.min(this.right, region.right);
3031         var b = Math.min(this.bottom, region.bottom);
3032         var l = Math.max(this.left, region.left);
3033
3034         if (b >= t && r >= l) {
3035             return new Roo.lib.Region(t, r, b, l);
3036         } else {
3037             return null;
3038         }
3039     },
3040     union : function(region) {
3041         var t = Math.min(this.top, region.top);
3042         var r = Math.max(this.right, region.right);
3043         var b = Math.max(this.bottom, region.bottom);
3044         var l = Math.min(this.left, region.left);
3045
3046         return new Roo.lib.Region(t, r, b, l);
3047     },
3048
3049     adjust : function(t, l, b, r) {
3050         this.top += t;
3051         this.left += l;
3052         this.right += r;
3053         this.bottom += b;
3054         return this;
3055     }
3056 };
3057
3058 Roo.lib.Region.getRegion = function(el) {
3059     var p = Roo.lib.Dom.getXY(el);
3060
3061     var t = p[1];
3062     var r = p[0] + el.offsetWidth;
3063     var b = p[1] + el.offsetHeight;
3064     var l = p[0];
3065
3066     return new Roo.lib.Region(t, r, b, l);
3067 };
3068 /*
3069  * Portions of this file are based on pieces of Yahoo User Interface Library
3070  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071  * YUI licensed under the BSD License:
3072  * http://developer.yahoo.net/yui/license.txt
3073  * <script type="text/javascript">
3074  *
3075  */
3076 //@@dep Roo.lib.Region
3077
3078
3079 Roo.lib.Point = function(x, y) {
3080     if (x instanceof Array) {
3081         y = x[1];
3082         x = x[0];
3083     }
3084     this.x = this.right = this.left = this[0] = x;
3085     this.y = this.top = this.bottom = this[1] = y;
3086 };
3087
3088 Roo.lib.Point.prototype = new Roo.lib.Region();
3089 /*
3090  * Portions of this file are based on pieces of Yahoo User Interface Library
3091  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3092  * YUI licensed under the BSD License:
3093  * http://developer.yahoo.net/yui/license.txt
3094  * <script type="text/javascript">
3095  *
3096  */
3097  
3098 (function() {   
3099
3100     Roo.lib.Anim = {
3101         scroll : function(el, args, duration, easing, cb, scope) {
3102             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3103         },
3104
3105         motion : function(el, args, duration, easing, cb, scope) {
3106             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3107         },
3108
3109         color : function(el, args, duration, easing, cb, scope) {
3110             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3111         },
3112
3113         run : function(el, args, duration, easing, cb, scope, type) {
3114             type = type || Roo.lib.AnimBase;
3115             if (typeof easing == "string") {
3116                 easing = Roo.lib.Easing[easing];
3117             }
3118             var anim = new type(el, args, duration, easing);
3119             anim.animateX(function() {
3120                 Roo.callback(cb, scope);
3121             });
3122             return anim;
3123         }
3124     };
3125 })();/*
3126  * Portions of this file are based on pieces of Yahoo User Interface Library
3127  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3128  * YUI licensed under the BSD License:
3129  * http://developer.yahoo.net/yui/license.txt
3130  * <script type="text/javascript">
3131  *
3132  */
3133
3134 (function() {    
3135     var libFlyweight;
3136     
3137     function fly(el) {
3138         if (!libFlyweight) {
3139             libFlyweight = new Roo.Element.Flyweight();
3140         }
3141         libFlyweight.dom = el;
3142         return libFlyweight;
3143     }
3144
3145     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3146     
3147    
3148     
3149     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3150         if (el) {
3151             this.init(el, attributes, duration, method);
3152         }
3153     };
3154
3155     Roo.lib.AnimBase.fly = fly;
3156     
3157     
3158     
3159     Roo.lib.AnimBase.prototype = {
3160
3161         toString: function() {
3162             var el = this.getEl();
3163             var id = el.id || el.tagName;
3164             return ("Anim " + id);
3165         },
3166
3167         patterns: {
3168             noNegatives:        /width|height|opacity|padding/i,
3169             offsetAttribute:  /^((width|height)|(top|left))$/,
3170             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3171             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3172         },
3173
3174
3175         doMethod: function(attr, start, end) {
3176             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3177         },
3178
3179
3180         setAttribute: function(attr, val, unit) {
3181             if (this.patterns.noNegatives.test(attr)) {
3182                 val = (val > 0) ? val : 0;
3183             }
3184
3185             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3186         },
3187
3188
3189         getAttribute: function(attr) {
3190             var el = this.getEl();
3191             var val = fly(el).getStyle(attr);
3192
3193             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3194                 return parseFloat(val);
3195             }
3196
3197             var a = this.patterns.offsetAttribute.exec(attr) || [];
3198             var pos = !!( a[3] );
3199             var box = !!( a[2] );
3200
3201
3202             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3203                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3204             } else {
3205                 val = 0;
3206             }
3207
3208             return val;
3209         },
3210
3211
3212         getDefaultUnit: function(attr) {
3213             if (this.patterns.defaultUnit.test(attr)) {
3214                 return 'px';
3215             }
3216
3217             return '';
3218         },
3219
3220         animateX : function(callback, scope) {
3221             var f = function() {
3222                 this.onComplete.removeListener(f);
3223                 if (typeof callback == "function") {
3224                     callback.call(scope || this, this);
3225                 }
3226             };
3227             this.onComplete.addListener(f, this);
3228             this.animate();
3229         },
3230
3231
3232         setRuntimeAttribute: function(attr) {
3233             var start;
3234             var end;
3235             var attributes = this.attributes;
3236
3237             this.runtimeAttributes[attr] = {};
3238
3239             var isset = function(prop) {
3240                 return (typeof prop !== 'undefined');
3241             };
3242
3243             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3244                 return false;
3245             }
3246
3247             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3248
3249
3250             if (isset(attributes[attr]['to'])) {
3251                 end = attributes[attr]['to'];
3252             } else if (isset(attributes[attr]['by'])) {
3253                 if (start.constructor == Array) {
3254                     end = [];
3255                     for (var i = 0, len = start.length; i < len; ++i) {
3256                         end[i] = start[i] + attributes[attr]['by'][i];
3257                     }
3258                 } else {
3259                     end = start + attributes[attr]['by'];
3260                 }
3261             }
3262
3263             this.runtimeAttributes[attr].start = start;
3264             this.runtimeAttributes[attr].end = end;
3265
3266
3267             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3268         },
3269
3270
3271         init: function(el, attributes, duration, method) {
3272
3273             var isAnimated = false;
3274
3275
3276             var startTime = null;
3277
3278
3279             var actualFrames = 0;
3280
3281
3282             el = Roo.getDom(el);
3283
3284
3285             this.attributes = attributes || {};
3286
3287
3288             this.duration = duration || 1;
3289
3290
3291             this.method = method || Roo.lib.Easing.easeNone;
3292
3293
3294             this.useSeconds = true;
3295
3296
3297             this.currentFrame = 0;
3298
3299
3300             this.totalFrames = Roo.lib.AnimMgr.fps;
3301
3302
3303             this.getEl = function() {
3304                 return el;
3305             };
3306
3307
3308             this.isAnimated = function() {
3309                 return isAnimated;
3310             };
3311
3312
3313             this.getStartTime = function() {
3314                 return startTime;
3315             };
3316
3317             this.runtimeAttributes = {};
3318
3319
3320             this.animate = function() {
3321                 if (this.isAnimated()) {
3322                     return false;
3323                 }
3324
3325                 this.currentFrame = 0;
3326
3327                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3328
3329                 Roo.lib.AnimMgr.registerElement(this);
3330             };
3331
3332
3333             this.stop = function(finish) {
3334                 if (finish) {
3335                     this.currentFrame = this.totalFrames;
3336                     this._onTween.fire();
3337                 }
3338                 Roo.lib.AnimMgr.stop(this);
3339             };
3340
3341             var onStart = function() {
3342                 this.onStart.fire();
3343
3344                 this.runtimeAttributes = {};
3345                 for (var attr in this.attributes) {
3346                     this.setRuntimeAttribute(attr);
3347                 }
3348
3349                 isAnimated = true;
3350                 actualFrames = 0;
3351                 startTime = new Date();
3352             };
3353
3354
3355             var onTween = function() {
3356                 var data = {
3357                     duration: new Date() - this.getStartTime(),
3358                     currentFrame: this.currentFrame
3359                 };
3360
3361                 data.toString = function() {
3362                     return (
3363                             'duration: ' + data.duration +
3364                             ', currentFrame: ' + data.currentFrame
3365                             );
3366                 };
3367
3368                 this.onTween.fire(data);
3369
3370                 var runtimeAttributes = this.runtimeAttributes;
3371
3372                 for (var attr in runtimeAttributes) {
3373                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3374                 }
3375
3376                 actualFrames += 1;
3377             };
3378
3379             var onComplete = function() {
3380                 var actual_duration = (new Date() - startTime) / 1000 ;
3381
3382                 var data = {
3383                     duration: actual_duration,
3384                     frames: actualFrames,
3385                     fps: actualFrames / actual_duration
3386                 };
3387
3388                 data.toString = function() {
3389                     return (
3390                             'duration: ' + data.duration +
3391                             ', frames: ' + data.frames +
3392                             ', fps: ' + data.fps
3393                             );
3394                 };
3395
3396                 isAnimated = false;
3397                 actualFrames = 0;
3398                 this.onComplete.fire(data);
3399             };
3400
3401
3402             this._onStart = new Roo.util.Event(this);
3403             this.onStart = new Roo.util.Event(this);
3404             this.onTween = new Roo.util.Event(this);
3405             this._onTween = new Roo.util.Event(this);
3406             this.onComplete = new Roo.util.Event(this);
3407             this._onComplete = new Roo.util.Event(this);
3408             this._onStart.addListener(onStart);
3409             this._onTween.addListener(onTween);
3410             this._onComplete.addListener(onComplete);
3411         }
3412     };
3413 })();
3414 /*
3415  * Portions of this file are based on pieces of Yahoo User Interface Library
3416  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3417  * YUI licensed under the BSD License:
3418  * http://developer.yahoo.net/yui/license.txt
3419  * <script type="text/javascript">
3420  *
3421  */
3422
3423 Roo.lib.AnimMgr = new function() {
3424
3425     var thread = null;
3426
3427
3428     var queue = [];
3429
3430
3431     var tweenCount = 0;
3432
3433
3434     this.fps = 1000;
3435
3436
3437     this.delay = 1;
3438
3439
3440     this.registerElement = function(tween) {
3441         queue[queue.length] = tween;
3442         tweenCount += 1;
3443         tween._onStart.fire();
3444         this.start();
3445     };
3446
3447
3448     this.unRegister = function(tween, index) {
3449         tween._onComplete.fire();
3450         index = index || getIndex(tween);
3451         if (index != -1) {
3452             queue.splice(index, 1);
3453         }
3454
3455         tweenCount -= 1;
3456         if (tweenCount <= 0) {
3457             this.stop();
3458         }
3459     };
3460
3461
3462     this.start = function() {
3463         if (thread === null) {
3464             thread = setInterval(this.run, this.delay);
3465         }
3466     };
3467
3468
3469     this.stop = function(tween) {
3470         if (!tween) {
3471             clearInterval(thread);
3472
3473             for (var i = 0, len = queue.length; i < len; ++i) {
3474                 if (queue[0].isAnimated()) {
3475                     this.unRegister(queue[0], 0);
3476                 }
3477             }
3478
3479             queue = [];
3480             thread = null;
3481             tweenCount = 0;
3482         }
3483         else {
3484             this.unRegister(tween);
3485         }
3486     };
3487
3488
3489     this.run = function() {
3490         for (var i = 0, len = queue.length; i < len; ++i) {
3491             var tween = queue[i];
3492             if (!tween || !tween.isAnimated()) {
3493                 continue;
3494             }
3495
3496             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3497             {
3498                 tween.currentFrame += 1;
3499
3500                 if (tween.useSeconds) {
3501                     correctFrame(tween);
3502                 }
3503                 tween._onTween.fire();
3504             }
3505             else {
3506                 Roo.lib.AnimMgr.stop(tween, i);
3507             }
3508         }
3509     };
3510
3511     var getIndex = function(anim) {
3512         for (var i = 0, len = queue.length; i < len; ++i) {
3513             if (queue[i] == anim) {
3514                 return i;
3515             }
3516         }
3517         return -1;
3518     };
3519
3520
3521     var correctFrame = function(tween) {
3522         var frames = tween.totalFrames;
3523         var frame = tween.currentFrame;
3524         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3525         var elapsed = (new Date() - tween.getStartTime());
3526         var tweak = 0;
3527
3528         if (elapsed < tween.duration * 1000) {
3529             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3530         } else {
3531             tweak = frames - (frame + 1);
3532         }
3533         if (tweak > 0 && isFinite(tweak)) {
3534             if (tween.currentFrame + tweak >= frames) {
3535                 tweak = frames - (frame + 1);
3536             }
3537
3538             tween.currentFrame += tweak;
3539         }
3540     };
3541 };
3542
3543     /*
3544  * Portions of this file are based on pieces of Yahoo User Interface Library
3545  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3546  * YUI licensed under the BSD License:
3547  * http://developer.yahoo.net/yui/license.txt
3548  * <script type="text/javascript">
3549  *
3550  */
3551 Roo.lib.Bezier = new function() {
3552
3553         this.getPosition = function(points, t) {
3554             var n = points.length;
3555             var tmp = [];
3556
3557             for (var i = 0; i < n; ++i) {
3558                 tmp[i] = [points[i][0], points[i][1]];
3559             }
3560
3561             for (var j = 1; j < n; ++j) {
3562                 for (i = 0; i < n - j; ++i) {
3563                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3564                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3565                 }
3566             }
3567
3568             return [ tmp[0][0], tmp[0][1] ];
3569
3570         };
3571     };/*
3572  * Portions of this file are based on pieces of Yahoo User Interface Library
3573  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3574  * YUI licensed under the BSD License:
3575  * http://developer.yahoo.net/yui/license.txt
3576  * <script type="text/javascript">
3577  *
3578  */
3579 (function() {
3580
3581     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3582         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3583     };
3584
3585     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3586
3587     var fly = Roo.lib.AnimBase.fly;
3588     var Y = Roo.lib;
3589     var superclass = Y.ColorAnim.superclass;
3590     var proto = Y.ColorAnim.prototype;
3591
3592     proto.toString = function() {
3593         var el = this.getEl();
3594         var id = el.id || el.tagName;
3595         return ("ColorAnim " + id);
3596     };
3597
3598     proto.patterns.color = /color$/i;
3599     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3600     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3601     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3602     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3603
3604
3605     proto.parseColor = function(s) {
3606         if (s.length == 3) {
3607             return s;
3608         }
3609
3610         var c = this.patterns.hex.exec(s);
3611         if (c && c.length == 4) {
3612             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3613         }
3614
3615         c = this.patterns.rgb.exec(s);
3616         if (c && c.length == 4) {
3617             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3618         }
3619
3620         c = this.patterns.hex3.exec(s);
3621         if (c && c.length == 4) {
3622             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3623         }
3624
3625         return null;
3626     };
3627     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3628     proto.getAttribute = function(attr) {
3629         var el = this.getEl();
3630         if (this.patterns.color.test(attr)) {
3631             var val = fly(el).getStyle(attr);
3632
3633             if (this.patterns.transparent.test(val)) {
3634                 var parent = el.parentNode;
3635                 val = fly(parent).getStyle(attr);
3636
3637                 while (parent && this.patterns.transparent.test(val)) {
3638                     parent = parent.parentNode;
3639                     val = fly(parent).getStyle(attr);
3640                     if (parent.tagName.toUpperCase() == 'HTML') {
3641                         val = '#fff';
3642                     }
3643                 }
3644             }
3645         } else {
3646             val = superclass.getAttribute.call(this, attr);
3647         }
3648
3649         return val;
3650     };
3651     proto.getAttribute = function(attr) {
3652         var el = this.getEl();
3653         if (this.patterns.color.test(attr)) {
3654             var val = fly(el).getStyle(attr);
3655
3656             if (this.patterns.transparent.test(val)) {
3657                 var parent = el.parentNode;
3658                 val = fly(parent).getStyle(attr);
3659
3660                 while (parent && this.patterns.transparent.test(val)) {
3661                     parent = parent.parentNode;
3662                     val = fly(parent).getStyle(attr);
3663                     if (parent.tagName.toUpperCase() == 'HTML') {
3664                         val = '#fff';
3665                     }
3666                 }
3667             }
3668         } else {
3669             val = superclass.getAttribute.call(this, attr);
3670         }
3671
3672         return val;
3673     };
3674
3675     proto.doMethod = function(attr, start, end) {
3676         var val;
3677
3678         if (this.patterns.color.test(attr)) {
3679             val = [];
3680             for (var i = 0, len = start.length; i < len; ++i) {
3681                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3682             }
3683
3684             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3685         }
3686         else {
3687             val = superclass.doMethod.call(this, attr, start, end);
3688         }
3689
3690         return val;
3691     };
3692
3693     proto.setRuntimeAttribute = function(attr) {
3694         superclass.setRuntimeAttribute.call(this, attr);
3695
3696         if (this.patterns.color.test(attr)) {
3697             var attributes = this.attributes;
3698             var start = this.parseColor(this.runtimeAttributes[attr].start);
3699             var end = this.parseColor(this.runtimeAttributes[attr].end);
3700
3701             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3702                 end = this.parseColor(attributes[attr].by);
3703
3704                 for (var i = 0, len = start.length; i < len; ++i) {
3705                     end[i] = start[i] + end[i];
3706                 }
3707             }
3708
3709             this.runtimeAttributes[attr].start = start;
3710             this.runtimeAttributes[attr].end = end;
3711         }
3712     };
3713 })();
3714
3715 /*
3716  * Portions of this file are based on pieces of Yahoo User Interface Library
3717  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3718  * YUI licensed under the BSD License:
3719  * http://developer.yahoo.net/yui/license.txt
3720  * <script type="text/javascript">
3721  *
3722  */
3723 Roo.lib.Easing = {
3724
3725
3726     easeNone: function (t, b, c, d) {
3727         return c * t / d + b;
3728     },
3729
3730
3731     easeIn: function (t, b, c, d) {
3732         return c * (t /= d) * t + b;
3733     },
3734
3735
3736     easeOut: function (t, b, c, d) {
3737         return -c * (t /= d) * (t - 2) + b;
3738     },
3739
3740
3741     easeBoth: function (t, b, c, d) {
3742         if ((t /= d / 2) < 1) {
3743             return c / 2 * t * t + b;
3744         }
3745
3746         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3747     },
3748
3749
3750     easeInStrong: function (t, b, c, d) {
3751         return c * (t /= d) * t * t * t + b;
3752     },
3753
3754
3755     easeOutStrong: function (t, b, c, d) {
3756         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3757     },
3758
3759
3760     easeBothStrong: function (t, b, c, d) {
3761         if ((t /= d / 2) < 1) {
3762             return c / 2 * t * t * t * t + b;
3763         }
3764
3765         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3766     },
3767
3768
3769
3770     elasticIn: function (t, b, c, d, a, p) {
3771         if (t == 0) {
3772             return b;
3773         }
3774         if ((t /= d) == 1) {
3775             return b + c;
3776         }
3777         if (!p) {
3778             p = d * .3;
3779         }
3780
3781         if (!a || a < Math.abs(c)) {
3782             a = c;
3783             var s = p / 4;
3784         }
3785         else {
3786             var s = p / (2 * Math.PI) * Math.asin(c / a);
3787         }
3788
3789         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3790     },
3791
3792
3793     elasticOut: function (t, b, c, d, a, p) {
3794         if (t == 0) {
3795             return b;
3796         }
3797         if ((t /= d) == 1) {
3798             return b + c;
3799         }
3800         if (!p) {
3801             p = d * .3;
3802         }
3803
3804         if (!a || a < Math.abs(c)) {
3805             a = c;
3806             var s = p / 4;
3807         }
3808         else {
3809             var s = p / (2 * Math.PI) * Math.asin(c / a);
3810         }
3811
3812         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3813     },
3814
3815
3816     elasticBoth: function (t, b, c, d, a, p) {
3817         if (t == 0) {
3818             return b;
3819         }
3820
3821         if ((t /= d / 2) == 2) {
3822             return b + c;
3823         }
3824
3825         if (!p) {
3826             p = d * (.3 * 1.5);
3827         }
3828
3829         if (!a || a < Math.abs(c)) {
3830             a = c;
3831             var s = p / 4;
3832         }
3833         else {
3834             var s = p / (2 * Math.PI) * Math.asin(c / a);
3835         }
3836
3837         if (t < 1) {
3838             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3839                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3840         }
3841         return a * Math.pow(2, -10 * (t -= 1)) *
3842                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3843     },
3844
3845
3846
3847     backIn: function (t, b, c, d, s) {
3848         if (typeof s == 'undefined') {
3849             s = 1.70158;
3850         }
3851         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3852     },
3853
3854
3855     backOut: function (t, b, c, d, s) {
3856         if (typeof s == 'undefined') {
3857             s = 1.70158;
3858         }
3859         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3860     },
3861
3862
3863     backBoth: function (t, b, c, d, s) {
3864         if (typeof s == 'undefined') {
3865             s = 1.70158;
3866         }
3867
3868         if ((t /= d / 2 ) < 1) {
3869             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3870         }
3871         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3872     },
3873
3874
3875     bounceIn: function (t, b, c, d) {
3876         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3877     },
3878
3879
3880     bounceOut: function (t, b, c, d) {
3881         if ((t /= d) < (1 / 2.75)) {
3882             return c * (7.5625 * t * t) + b;
3883         } else if (t < (2 / 2.75)) {
3884             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3885         } else if (t < (2.5 / 2.75)) {
3886             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3887         }
3888         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3889     },
3890
3891
3892     bounceBoth: function (t, b, c, d) {
3893         if (t < d / 2) {
3894             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3895         }
3896         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3897     }
3898 };/*
3899  * Portions of this file are based on pieces of Yahoo User Interface Library
3900  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3901  * YUI licensed under the BSD License:
3902  * http://developer.yahoo.net/yui/license.txt
3903  * <script type="text/javascript">
3904  *
3905  */
3906     (function() {
3907         Roo.lib.Motion = function(el, attributes, duration, method) {
3908             if (el) {
3909                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3910             }
3911         };
3912
3913         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3914
3915
3916         var Y = Roo.lib;
3917         var superclass = Y.Motion.superclass;
3918         var proto = Y.Motion.prototype;
3919
3920         proto.toString = function() {
3921             var el = this.getEl();
3922             var id = el.id || el.tagName;
3923             return ("Motion " + id);
3924         };
3925
3926         proto.patterns.points = /^points$/i;
3927
3928         proto.setAttribute = function(attr, val, unit) {
3929             if (this.patterns.points.test(attr)) {
3930                 unit = unit || 'px';
3931                 superclass.setAttribute.call(this, 'left', val[0], unit);
3932                 superclass.setAttribute.call(this, 'top', val[1], unit);
3933             } else {
3934                 superclass.setAttribute.call(this, attr, val, unit);
3935             }
3936         };
3937
3938         proto.getAttribute = function(attr) {
3939             if (this.patterns.points.test(attr)) {
3940                 var val = [
3941                         superclass.getAttribute.call(this, 'left'),
3942                         superclass.getAttribute.call(this, 'top')
3943                         ];
3944             } else {
3945                 val = superclass.getAttribute.call(this, attr);
3946             }
3947
3948             return val;
3949         };
3950
3951         proto.doMethod = function(attr, start, end) {
3952             var val = null;
3953
3954             if (this.patterns.points.test(attr)) {
3955                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3956                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3957             } else {
3958                 val = superclass.doMethod.call(this, attr, start, end);
3959             }
3960             return val;
3961         };
3962
3963         proto.setRuntimeAttribute = function(attr) {
3964             if (this.patterns.points.test(attr)) {
3965                 var el = this.getEl();
3966                 var attributes = this.attributes;
3967                 var start;
3968                 var control = attributes['points']['control'] || [];
3969                 var end;
3970                 var i, len;
3971
3972                 if (control.length > 0 && !(control[0] instanceof Array)) {
3973                     control = [control];
3974                 } else {
3975                     var tmp = [];
3976                     for (i = 0,len = control.length; i < len; ++i) {
3977                         tmp[i] = control[i];
3978                     }
3979                     control = tmp;
3980                 }
3981
3982                 Roo.fly(el).position();
3983
3984                 if (isset(attributes['points']['from'])) {
3985                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3986                 }
3987                 else {
3988                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3989                 }
3990
3991                 start = this.getAttribute('points');
3992
3993
3994                 if (isset(attributes['points']['to'])) {
3995                     end = translateValues.call(this, attributes['points']['to'], start);
3996
3997                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3998                     for (i = 0,len = control.length; i < len; ++i) {
3999                         control[i] = translateValues.call(this, control[i], start);
4000                     }
4001
4002
4003                 } else if (isset(attributes['points']['by'])) {
4004                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4005
4006                     for (i = 0,len = control.length; i < len; ++i) {
4007                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4008                     }
4009                 }
4010
4011                 this.runtimeAttributes[attr] = [start];
4012
4013                 if (control.length > 0) {
4014                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4015                 }
4016
4017                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4018             }
4019             else {
4020                 superclass.setRuntimeAttribute.call(this, attr);
4021             }
4022         };
4023
4024         var translateValues = function(val, start) {
4025             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4026             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4027
4028             return val;
4029         };
4030
4031         var isset = function(prop) {
4032             return (typeof prop !== 'undefined');
4033         };
4034     })();
4035 /*
4036  * Portions of this file are based on pieces of Yahoo User Interface Library
4037  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4038  * YUI licensed under the BSD License:
4039  * http://developer.yahoo.net/yui/license.txt
4040  * <script type="text/javascript">
4041  *
4042  */
4043     (function() {
4044         Roo.lib.Scroll = function(el, attributes, duration, method) {
4045             if (el) {
4046                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4047             }
4048         };
4049
4050         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4051
4052
4053         var Y = Roo.lib;
4054         var superclass = Y.Scroll.superclass;
4055         var proto = Y.Scroll.prototype;
4056
4057         proto.toString = function() {
4058             var el = this.getEl();
4059             var id = el.id || el.tagName;
4060             return ("Scroll " + id);
4061         };
4062
4063         proto.doMethod = function(attr, start, end) {
4064             var val = null;
4065
4066             if (attr == 'scroll') {
4067                 val = [
4068                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4069                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4070                         ];
4071
4072             } else {
4073                 val = superclass.doMethod.call(this, attr, start, end);
4074             }
4075             return val;
4076         };
4077
4078         proto.getAttribute = function(attr) {
4079             var val = null;
4080             var el = this.getEl();
4081
4082             if (attr == 'scroll') {
4083                 val = [ el.scrollLeft, el.scrollTop ];
4084             } else {
4085                 val = superclass.getAttribute.call(this, attr);
4086             }
4087
4088             return val;
4089         };
4090
4091         proto.setAttribute = function(attr, val, unit) {
4092             var el = this.getEl();
4093
4094             if (attr == 'scroll') {
4095                 el.scrollLeft = val[0];
4096                 el.scrollTop = val[1];
4097             } else {
4098                 superclass.setAttribute.call(this, attr, val, unit);
4099             }
4100         };
4101     })();
4102 /*
4103  * Based on:
4104  * Ext JS Library 1.1.1
4105  * Copyright(c) 2006-2007, Ext JS, LLC.
4106  *
4107  * Originally Released Under LGPL - original licence link has changed is not relivant.
4108  *
4109  * Fork - LGPL
4110  * <script type="text/javascript">
4111  */
4112
4113
4114 // nasty IE9 hack - what a pile of crap that is..
4115
4116  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4117     Range.prototype.createContextualFragment = function (html) {
4118         var doc = window.document;
4119         var container = doc.createElement("div");
4120         container.innerHTML = html;
4121         var frag = doc.createDocumentFragment(), n;
4122         while ((n = container.firstChild)) {
4123             frag.appendChild(n);
4124         }
4125         return frag;
4126     };
4127 }
4128
4129 /**
4130  * @class Roo.DomHelper
4131  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4132  * 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>.
4133  * @singleton
4134  */
4135 Roo.DomHelper = function(){
4136     var tempTableEl = null;
4137     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4138     var tableRe = /^table|tbody|tr|td$/i;
4139     var xmlns = {};
4140     // build as innerHTML where available
4141     /** @ignore */
4142     var createHtml = function(o){
4143         if(typeof o == 'string'){
4144             return o;
4145         }
4146         var b = "";
4147         if(!o.tag){
4148             o.tag = "div";
4149         }
4150         b += "<" + o.tag;
4151         for(var attr in o){
4152             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4153             if(attr == "style"){
4154                 var s = o["style"];
4155                 if(typeof s == "function"){
4156                     s = s.call();
4157                 }
4158                 if(typeof s == "string"){
4159                     b += ' style="' + s + '"';
4160                 }else if(typeof s == "object"){
4161                     b += ' style="';
4162                     for(var key in s){
4163                         if(typeof s[key] != "function"){
4164                             b += key + ":" + s[key] + ";";
4165                         }
4166                     }
4167                     b += '"';
4168                 }
4169             }else{
4170                 if(attr == "cls"){
4171                     b += ' class="' + o["cls"] + '"';
4172                 }else if(attr == "htmlFor"){
4173                     b += ' for="' + o["htmlFor"] + '"';
4174                 }else{
4175                     b += " " + attr + '="' + o[attr] + '"';
4176                 }
4177             }
4178         }
4179         if(emptyTags.test(o.tag)){
4180             b += "/>";
4181         }else{
4182             b += ">";
4183             var cn = o.children || o.cn;
4184             if(cn){
4185                 //http://bugs.kde.org/show_bug.cgi?id=71506
4186                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4187                     for(var i = 0, len = cn.length; i < len; i++) {
4188                         b += createHtml(cn[i], b);
4189                     }
4190                 }else{
4191                     b += createHtml(cn, b);
4192                 }
4193             }
4194             if(o.html){
4195                 b += o.html;
4196             }
4197             b += "</" + o.tag + ">";
4198         }
4199         return b;
4200     };
4201
4202     // build as dom
4203     /** @ignore */
4204     var createDom = function(o, parentNode){
4205          
4206         // defininition craeted..
4207         var ns = false;
4208         if (o.ns && o.ns != 'html') {
4209                
4210             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4211                 xmlns[o.ns] = o.xmlns;
4212                 ns = o.xmlns;
4213             }
4214             if (typeof(xmlns[o.ns]) == 'undefined') {
4215                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4216             }
4217             ns = xmlns[o.ns];
4218         }
4219         
4220         
4221         if (typeof(o) == 'string') {
4222             return parentNode.appendChild(document.createTextNode(o));
4223         }
4224         o.tag = o.tag || div;
4225         if (o.ns && Roo.isIE) {
4226             ns = false;
4227             o.tag = o.ns + ':' + o.tag;
4228             
4229         }
4230         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4231         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4232         for(var attr in o){
4233             
4234             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4235                     attr == "style" || typeof o[attr] == "function") continue;
4236                     
4237             if(attr=="cls" && Roo.isIE){
4238                 el.className = o["cls"];
4239             }else{
4240                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4241                 else el[attr] = o[attr];
4242             }
4243         }
4244         Roo.DomHelper.applyStyles(el, o.style);
4245         var cn = o.children || o.cn;
4246         if(cn){
4247             //http://bugs.kde.org/show_bug.cgi?id=71506
4248              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4249                 for(var i = 0, len = cn.length; i < len; i++) {
4250                     createDom(cn[i], el);
4251                 }
4252             }else{
4253                 createDom(cn, el);
4254             }
4255         }
4256         if(o.html){
4257             el.innerHTML = o.html;
4258         }
4259         if(parentNode){
4260            parentNode.appendChild(el);
4261         }
4262         return el;
4263     };
4264
4265     var ieTable = function(depth, s, h, e){
4266         tempTableEl.innerHTML = [s, h, e].join('');
4267         var i = -1, el = tempTableEl;
4268         while(++i < depth){
4269             el = el.firstChild;
4270         }
4271         return el;
4272     };
4273
4274     // kill repeat to save bytes
4275     var ts = '<table>',
4276         te = '</table>',
4277         tbs = ts+'<tbody>',
4278         tbe = '</tbody>'+te,
4279         trs = tbs + '<tr>',
4280         tre = '</tr>'+tbe;
4281
4282     /**
4283      * @ignore
4284      * Nasty code for IE's broken table implementation
4285      */
4286     var insertIntoTable = function(tag, where, el, html){
4287         if(!tempTableEl){
4288             tempTableEl = document.createElement('div');
4289         }
4290         var node;
4291         var before = null;
4292         if(tag == 'td'){
4293             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4294                 return;
4295             }
4296             if(where == 'beforebegin'){
4297                 before = el;
4298                 el = el.parentNode;
4299             } else{
4300                 before = el.nextSibling;
4301                 el = el.parentNode;
4302             }
4303             node = ieTable(4, trs, html, tre);
4304         }
4305         else if(tag == 'tr'){
4306             if(where == 'beforebegin'){
4307                 before = el;
4308                 el = el.parentNode;
4309                 node = ieTable(3, tbs, html, tbe);
4310             } else if(where == 'afterend'){
4311                 before = el.nextSibling;
4312                 el = el.parentNode;
4313                 node = ieTable(3, tbs, html, tbe);
4314             } else{ // INTO a TR
4315                 if(where == 'afterbegin'){
4316                     before = el.firstChild;
4317                 }
4318                 node = ieTable(4, trs, html, tre);
4319             }
4320         } else if(tag == 'tbody'){
4321             if(where == 'beforebegin'){
4322                 before = el;
4323                 el = el.parentNode;
4324                 node = ieTable(2, ts, html, te);
4325             } else if(where == 'afterend'){
4326                 before = el.nextSibling;
4327                 el = el.parentNode;
4328                 node = ieTable(2, ts, html, te);
4329             } else{
4330                 if(where == 'afterbegin'){
4331                     before = el.firstChild;
4332                 }
4333                 node = ieTable(3, tbs, html, tbe);
4334             }
4335         } else{ // TABLE
4336             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4337                 return;
4338             }
4339             if(where == 'afterbegin'){
4340                 before = el.firstChild;
4341             }
4342             node = ieTable(2, ts, html, te);
4343         }
4344         el.insertBefore(node, before);
4345         return node;
4346     };
4347
4348     return {
4349     /** True to force the use of DOM instead of html fragments @type Boolean */
4350     useDom : false,
4351
4352     /**
4353      * Returns the markup for the passed Element(s) config
4354      * @param {Object} o The Dom object spec (and children)
4355      * @return {String}
4356      */
4357     markup : function(o){
4358         return createHtml(o);
4359     },
4360
4361     /**
4362      * Applies a style specification to an element
4363      * @param {String/HTMLElement} el The element to apply styles to
4364      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4365      * a function which returns such a specification.
4366      */
4367     applyStyles : function(el, styles){
4368         if(styles){
4369            el = Roo.fly(el);
4370            if(typeof styles == "string"){
4371                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4372                var matches;
4373                while ((matches = re.exec(styles)) != null){
4374                    el.setStyle(matches[1], matches[2]);
4375                }
4376            }else if (typeof styles == "object"){
4377                for (var style in styles){
4378                   el.setStyle(style, styles[style]);
4379                }
4380            }else if (typeof styles == "function"){
4381                 Roo.DomHelper.applyStyles(el, styles.call());
4382            }
4383         }
4384     },
4385
4386     /**
4387      * Inserts an HTML fragment into the Dom
4388      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4389      * @param {HTMLElement} el The context element
4390      * @param {String} html The HTML fragmenet
4391      * @return {HTMLElement} The new node
4392      */
4393     insertHtml : function(where, el, html){
4394         where = where.toLowerCase();
4395         if(el.insertAdjacentHTML){
4396             if(tableRe.test(el.tagName)){
4397                 var rs;
4398                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4399                     return rs;
4400                 }
4401             }
4402             switch(where){
4403                 case "beforebegin":
4404                     el.insertAdjacentHTML('BeforeBegin', html);
4405                     return el.previousSibling;
4406                 case "afterbegin":
4407                     el.insertAdjacentHTML('AfterBegin', html);
4408                     return el.firstChild;
4409                 case "beforeend":
4410                     el.insertAdjacentHTML('BeforeEnd', html);
4411                     return el.lastChild;
4412                 case "afterend":
4413                     el.insertAdjacentHTML('AfterEnd', html);
4414                     return el.nextSibling;
4415             }
4416             throw 'Illegal insertion point -> "' + where + '"';
4417         }
4418         var range = el.ownerDocument.createRange();
4419         var frag;
4420         switch(where){
4421              case "beforebegin":
4422                 range.setStartBefore(el);
4423                 frag = range.createContextualFragment(html);
4424                 el.parentNode.insertBefore(frag, el);
4425                 return el.previousSibling;
4426              case "afterbegin":
4427                 if(el.firstChild){
4428                     range.setStartBefore(el.firstChild);
4429                     frag = range.createContextualFragment(html);
4430                     el.insertBefore(frag, el.firstChild);
4431                     return el.firstChild;
4432                 }else{
4433                     el.innerHTML = html;
4434                     return el.firstChild;
4435                 }
4436             case "beforeend":
4437                 if(el.lastChild){
4438                     range.setStartAfter(el.lastChild);
4439                     frag = range.createContextualFragment(html);
4440                     el.appendChild(frag);
4441                     return el.lastChild;
4442                 }else{
4443                     el.innerHTML = html;
4444                     return el.lastChild;
4445                 }
4446             case "afterend":
4447                 range.setStartAfter(el);
4448                 frag = range.createContextualFragment(html);
4449                 el.parentNode.insertBefore(frag, el.nextSibling);
4450                 return el.nextSibling;
4451             }
4452             throw 'Illegal insertion point -> "' + where + '"';
4453     },
4454
4455     /**
4456      * Creates new Dom element(s) and inserts them before el
4457      * @param {String/HTMLElement/Element} el The context element
4458      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4459      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4460      * @return {HTMLElement/Roo.Element} The new node
4461      */
4462     insertBefore : function(el, o, returnElement){
4463         return this.doInsert(el, o, returnElement, "beforeBegin");
4464     },
4465
4466     /**
4467      * Creates new Dom element(s) and inserts them after el
4468      * @param {String/HTMLElement/Element} el The context element
4469      * @param {Object} o The Dom object spec (and children)
4470      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4471      * @return {HTMLElement/Roo.Element} The new node
4472      */
4473     insertAfter : function(el, o, returnElement){
4474         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4475     },
4476
4477     /**
4478      * Creates new Dom element(s) and inserts them as the first child of el
4479      * @param {String/HTMLElement/Element} el The context element
4480      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4481      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4482      * @return {HTMLElement/Roo.Element} The new node
4483      */
4484     insertFirst : function(el, o, returnElement){
4485         return this.doInsert(el, o, returnElement, "afterBegin");
4486     },
4487
4488     // private
4489     doInsert : function(el, o, returnElement, pos, sibling){
4490         el = Roo.getDom(el);
4491         var newNode;
4492         if(this.useDom || o.ns){
4493             newNode = createDom(o, null);
4494             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4495         }else{
4496             var html = createHtml(o);
4497             newNode = this.insertHtml(pos, el, html);
4498         }
4499         return returnElement ? Roo.get(newNode, true) : newNode;
4500     },
4501
4502     /**
4503      * Creates new Dom element(s) and appends them to el
4504      * @param {String/HTMLElement/Element} el The context element
4505      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4506      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4507      * @return {HTMLElement/Roo.Element} The new node
4508      */
4509     append : function(el, o, returnElement){
4510         el = Roo.getDom(el);
4511         var newNode;
4512         if(this.useDom || o.ns){
4513             newNode = createDom(o, null);
4514             el.appendChild(newNode);
4515         }else{
4516             var html = createHtml(o);
4517             newNode = this.insertHtml("beforeEnd", el, html);
4518         }
4519         return returnElement ? Roo.get(newNode, true) : newNode;
4520     },
4521
4522     /**
4523      * Creates new Dom element(s) and overwrites the contents of el with them
4524      * @param {String/HTMLElement/Element} el The context element
4525      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4526      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4527      * @return {HTMLElement/Roo.Element} The new node
4528      */
4529     overwrite : function(el, o, returnElement){
4530         el = Roo.getDom(el);
4531         if (o.ns) {
4532           
4533             while (el.childNodes.length) {
4534                 el.removeChild(el.firstChild);
4535             }
4536             createDom(o, el);
4537         } else {
4538             el.innerHTML = createHtml(o);   
4539         }
4540         
4541         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4542     },
4543
4544     /**
4545      * Creates a new Roo.DomHelper.Template from the Dom object spec
4546      * @param {Object} o The Dom object spec (and children)
4547      * @return {Roo.DomHelper.Template} The new template
4548      */
4549     createTemplate : function(o){
4550         var html = createHtml(o);
4551         return new Roo.Template(html);
4552     }
4553     };
4554 }();
4555 /*
4556  * Based on:
4557  * Ext JS Library 1.1.1
4558  * Copyright(c) 2006-2007, Ext JS, LLC.
4559  *
4560  * Originally Released Under LGPL - original licence link has changed is not relivant.
4561  *
4562  * Fork - LGPL
4563  * <script type="text/javascript">
4564  */
4565  
4566 /**
4567 * @class Roo.Template
4568 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4569 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4570 * Usage:
4571 <pre><code>
4572 var t = new Roo.Template({
4573     html :  '&lt;div name="{id}"&gt;' + 
4574         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4575         '&lt;/div&gt;',
4576     myformat: function (value, allValues) {
4577         return 'XX' + value;
4578     }
4579 });
4580 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4581 </code></pre>
4582 * For more information see this blog post with examples:
4583 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4584      - Create Elements using DOM, HTML fragments and Templates</a>. 
4585 * @constructor
4586 * @param {Object} cfg - Configuration object.
4587 */
4588 Roo.Template = function(cfg){
4589     // BC!
4590     if(cfg instanceof Array){
4591         cfg = cfg.join("");
4592     }else if(arguments.length > 1){
4593         cfg = Array.prototype.join.call(arguments, "");
4594     }
4595     
4596     
4597     if (typeof(cfg) == 'object') {
4598         Roo.apply(this,cfg)
4599     } else {
4600         // bc
4601         this.html = cfg;
4602     }
4603     if (this.url) {
4604         this.load();
4605     }
4606     
4607 };
4608 Roo.Template.prototype = {
4609     
4610     /**
4611      * @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..
4612      *                    it should be fixed so that template is observable...
4613      */
4614     url : false,
4615     /**
4616      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4617      */
4618     html : '',
4619     /**
4620      * Returns an HTML fragment of this template with the specified values applied.
4621      * @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'})
4622      * @return {String} The HTML fragment
4623      */
4624     applyTemplate : function(values){
4625         try {
4626            
4627             if(this.compiled){
4628                 return this.compiled(values);
4629             }
4630             var useF = this.disableFormats !== true;
4631             var fm = Roo.util.Format, tpl = this;
4632             var fn = function(m, name, format, args){
4633                 if(format && useF){
4634                     if(format.substr(0, 5) == "this."){
4635                         return tpl.call(format.substr(5), values[name], values);
4636                     }else{
4637                         if(args){
4638                             // quoted values are required for strings in compiled templates, 
4639                             // but for non compiled we need to strip them
4640                             // quoted reversed for jsmin
4641                             var re = /^\s*['"](.*)["']\s*$/;
4642                             args = args.split(',');
4643                             for(var i = 0, len = args.length; i < len; i++){
4644                                 args[i] = args[i].replace(re, "$1");
4645                             }
4646                             args = [values[name]].concat(args);
4647                         }else{
4648                             args = [values[name]];
4649                         }
4650                         return fm[format].apply(fm, args);
4651                     }
4652                 }else{
4653                     return values[name] !== undefined ? values[name] : "";
4654                 }
4655             };
4656             return this.html.replace(this.re, fn);
4657         } catch (e) {
4658             Roo.log(e);
4659             throw e;
4660         }
4661          
4662     },
4663     
4664     loading : false,
4665       
4666     load : function ()
4667     {
4668          
4669         if (this.loading) {
4670             return;
4671         }
4672         var _t = this;
4673         
4674         this.loading = true;
4675         this.compiled = false;
4676         
4677         var cx = new Roo.data.Connection();
4678         cx.request({
4679             url : this.url,
4680             method : 'GET',
4681             success : function (response) {
4682                 _t.loading = false;
4683                 _t.html = response.responseText;
4684                 _t.url = false;
4685                 _t.compile();
4686              },
4687             failure : function(response) {
4688                 Roo.log("Template failed to load from " + _t.url);
4689                 _t.loading = false;
4690             }
4691         });
4692     },
4693
4694     /**
4695      * Sets the HTML used as the template and optionally compiles it.
4696      * @param {String} html
4697      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4698      * @return {Roo.Template} this
4699      */
4700     set : function(html, compile){
4701         this.html = html;
4702         this.compiled = null;
4703         if(compile){
4704             this.compile();
4705         }
4706         return this;
4707     },
4708     
4709     /**
4710      * True to disable format functions (defaults to false)
4711      * @type Boolean
4712      */
4713     disableFormats : false,
4714     
4715     /**
4716     * The regular expression used to match template variables 
4717     * @type RegExp
4718     * @property 
4719     */
4720     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4721     
4722     /**
4723      * Compiles the template into an internal function, eliminating the RegEx overhead.
4724      * @return {Roo.Template} this
4725      */
4726     compile : function(){
4727         var fm = Roo.util.Format;
4728         var useF = this.disableFormats !== true;
4729         var sep = Roo.isGecko ? "+" : ",";
4730         var fn = function(m, name, format, args){
4731             if(format && useF){
4732                 args = args ? ',' + args : "";
4733                 if(format.substr(0, 5) != "this."){
4734                     format = "fm." + format + '(';
4735                 }else{
4736                     format = 'this.call("'+ format.substr(5) + '", ';
4737                     args = ", values";
4738                 }
4739             }else{
4740                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4741             }
4742             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4743         };
4744         var body;
4745         // branched to use + in gecko and [].join() in others
4746         if(Roo.isGecko){
4747             body = "this.compiled = function(values){ return '" +
4748                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4749                     "';};";
4750         }else{
4751             body = ["this.compiled = function(values){ return ['"];
4752             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4753             body.push("'].join('');};");
4754             body = body.join('');
4755         }
4756         /**
4757          * eval:var:values
4758          * eval:var:fm
4759          */
4760         eval(body);
4761         return this;
4762     },
4763     
4764     // private function used to call members
4765     call : function(fnName, value, allValues){
4766         return this[fnName](value, allValues);
4767     },
4768     
4769     /**
4770      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4771      * @param {String/HTMLElement/Roo.Element} el The context element
4772      * @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'})
4773      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4774      * @return {HTMLElement/Roo.Element} The new node or Element
4775      */
4776     insertFirst: function(el, values, returnElement){
4777         return this.doInsert('afterBegin', el, values, returnElement);
4778     },
4779
4780     /**
4781      * Applies the supplied values to the template and inserts the new node(s) before el.
4782      * @param {String/HTMLElement/Roo.Element} el The context element
4783      * @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'})
4784      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4785      * @return {HTMLElement/Roo.Element} The new node or Element
4786      */
4787     insertBefore: function(el, values, returnElement){
4788         return this.doInsert('beforeBegin', el, values, returnElement);
4789     },
4790
4791     /**
4792      * Applies the supplied values to the template and inserts the new node(s) after el.
4793      * @param {String/HTMLElement/Roo.Element} el The context element
4794      * @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'})
4795      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4796      * @return {HTMLElement/Roo.Element} The new node or Element
4797      */
4798     insertAfter : function(el, values, returnElement){
4799         return this.doInsert('afterEnd', el, values, returnElement);
4800     },
4801     
4802     /**
4803      * Applies the supplied values to the template and appends the new node(s) to el.
4804      * @param {String/HTMLElement/Roo.Element} el The context element
4805      * @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'})
4806      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4807      * @return {HTMLElement/Roo.Element} The new node or Element
4808      */
4809     append : function(el, values, returnElement){
4810         return this.doInsert('beforeEnd', el, values, returnElement);
4811     },
4812
4813     doInsert : function(where, el, values, returnEl){
4814         el = Roo.getDom(el);
4815         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4816         return returnEl ? Roo.get(newNode, true) : newNode;
4817     },
4818
4819     /**
4820      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4821      * @param {String/HTMLElement/Roo.Element} el The context element
4822      * @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'})
4823      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4824      * @return {HTMLElement/Roo.Element} The new node or Element
4825      */
4826     overwrite : function(el, values, returnElement){
4827         el = Roo.getDom(el);
4828         el.innerHTML = this.applyTemplate(values);
4829         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4830     }
4831 };
4832 /**
4833  * Alias for {@link #applyTemplate}
4834  * @method
4835  */
4836 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4837
4838 // backwards compat
4839 Roo.DomHelper.Template = Roo.Template;
4840
4841 /**
4842  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4843  * @param {String/HTMLElement} el A DOM element or its id
4844  * @returns {Roo.Template} The created template
4845  * @static
4846  */
4847 Roo.Template.from = function(el){
4848     el = Roo.getDom(el);
4849     return new Roo.Template(el.value || el.innerHTML);
4850 };/*
4851  * Based on:
4852  * Ext JS Library 1.1.1
4853  * Copyright(c) 2006-2007, Ext JS, LLC.
4854  *
4855  * Originally Released Under LGPL - original licence link has changed is not relivant.
4856  *
4857  * Fork - LGPL
4858  * <script type="text/javascript">
4859  */
4860  
4861
4862 /*
4863  * This is code is also distributed under MIT license for use
4864  * with jQuery and prototype JavaScript libraries.
4865  */
4866 /**
4867  * @class Roo.DomQuery
4868 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).
4869 <p>
4870 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>
4871
4872 <p>
4873 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.
4874 </p>
4875 <h4>Element Selectors:</h4>
4876 <ul class="list">
4877     <li> <b>*</b> any element</li>
4878     <li> <b>E</b> an element with the tag E</li>
4879     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4880     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4881     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4882     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4883 </ul>
4884 <h4>Attribute Selectors:</h4>
4885 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4886 <ul class="list">
4887     <li> <b>E[foo]</b> has an attribute "foo"</li>
4888     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4889     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4890     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4891     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4892     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4893     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4894 </ul>
4895 <h4>Pseudo Classes:</h4>
4896 <ul class="list">
4897     <li> <b>E:first-child</b> E is the first child of its parent</li>
4898     <li> <b>E:last-child</b> E is the last child of its parent</li>
4899     <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>
4900     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4901     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4902     <li> <b>E:only-child</b> E is the only child of its parent</li>
4903     <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>
4904     <li> <b>E:first</b> the first E in the resultset</li>
4905     <li> <b>E:last</b> the last E in the resultset</li>
4906     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4907     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4908     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4909     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4910     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4911     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4912     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4913     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4914     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4915 </ul>
4916 <h4>CSS Value Selectors:</h4>
4917 <ul class="list">
4918     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4919     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4920     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4921     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4922     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4923     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4924 </ul>
4925  * @singleton
4926  */
4927 Roo.DomQuery = function(){
4928     var cache = {}, simpleCache = {}, valueCache = {};
4929     var nonSpace = /\S/;
4930     var trimRe = /^\s+|\s+$/g;
4931     var tplRe = /\{(\d+)\}/g;
4932     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4933     var tagTokenRe = /^(#)?([\w-\*]+)/;
4934     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4935
4936     function child(p, index){
4937         var i = 0;
4938         var n = p.firstChild;
4939         while(n){
4940             if(n.nodeType == 1){
4941                if(++i == index){
4942                    return n;
4943                }
4944             }
4945             n = n.nextSibling;
4946         }
4947         return null;
4948     };
4949
4950     function next(n){
4951         while((n = n.nextSibling) && n.nodeType != 1);
4952         return n;
4953     };
4954
4955     function prev(n){
4956         while((n = n.previousSibling) && n.nodeType != 1);
4957         return n;
4958     };
4959
4960     function children(d){
4961         var n = d.firstChild, ni = -1;
4962             while(n){
4963                 var nx = n.nextSibling;
4964                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4965                     d.removeChild(n);
4966                 }else{
4967                     n.nodeIndex = ++ni;
4968                 }
4969                 n = nx;
4970             }
4971             return this;
4972         };
4973
4974     function byClassName(c, a, v){
4975         if(!v){
4976             return c;
4977         }
4978         var r = [], ri = -1, cn;
4979         for(var i = 0, ci; ci = c[i]; i++){
4980             if((' '+ci.className+' ').indexOf(v) != -1){
4981                 r[++ri] = ci;
4982             }
4983         }
4984         return r;
4985     };
4986
4987     function attrValue(n, attr){
4988         if(!n.tagName && typeof n.length != "undefined"){
4989             n = n[0];
4990         }
4991         if(!n){
4992             return null;
4993         }
4994         if(attr == "for"){
4995             return n.htmlFor;
4996         }
4997         if(attr == "class" || attr == "className"){
4998             return n.className;
4999         }
5000         return n.getAttribute(attr) || n[attr];
5001
5002     };
5003
5004     function getNodes(ns, mode, tagName){
5005         var result = [], ri = -1, cs;
5006         if(!ns){
5007             return result;
5008         }
5009         tagName = tagName || "*";
5010         if(typeof ns.getElementsByTagName != "undefined"){
5011             ns = [ns];
5012         }
5013         if(!mode){
5014             for(var i = 0, ni; ni = ns[i]; i++){
5015                 cs = ni.getElementsByTagName(tagName);
5016                 for(var j = 0, ci; ci = cs[j]; j++){
5017                     result[++ri] = ci;
5018                 }
5019             }
5020         }else if(mode == "/" || mode == ">"){
5021             var utag = tagName.toUpperCase();
5022             for(var i = 0, ni, cn; ni = ns[i]; i++){
5023                 cn = ni.children || ni.childNodes;
5024                 for(var j = 0, cj; cj = cn[j]; j++){
5025                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5026                         result[++ri] = cj;
5027                     }
5028                 }
5029             }
5030         }else if(mode == "+"){
5031             var utag = tagName.toUpperCase();
5032             for(var i = 0, n; n = ns[i]; i++){
5033                 while((n = n.nextSibling) && n.nodeType != 1);
5034                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5035                     result[++ri] = n;
5036                 }
5037             }
5038         }else if(mode == "~"){
5039             for(var i = 0, n; n = ns[i]; i++){
5040                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5041                 if(n){
5042                     result[++ri] = n;
5043                 }
5044             }
5045         }
5046         return result;
5047     };
5048
5049     function concat(a, b){
5050         if(b.slice){
5051             return a.concat(b);
5052         }
5053         for(var i = 0, l = b.length; i < l; i++){
5054             a[a.length] = b[i];
5055         }
5056         return a;
5057     }
5058
5059     function byTag(cs, tagName){
5060         if(cs.tagName || cs == document){
5061             cs = [cs];
5062         }
5063         if(!tagName){
5064             return cs;
5065         }
5066         var r = [], ri = -1;
5067         tagName = tagName.toLowerCase();
5068         for(var i = 0, ci; ci = cs[i]; i++){
5069             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5070                 r[++ri] = ci;
5071             }
5072         }
5073         return r;
5074     };
5075
5076     function byId(cs, attr, id){
5077         if(cs.tagName || cs == document){
5078             cs = [cs];
5079         }
5080         if(!id){
5081             return cs;
5082         }
5083         var r = [], ri = -1;
5084         for(var i = 0,ci; ci = cs[i]; i++){
5085             if(ci && ci.id == id){
5086                 r[++ri] = ci;
5087                 return r;
5088             }
5089         }
5090         return r;
5091     };
5092
5093     function byAttribute(cs, attr, value, op, custom){
5094         var r = [], ri = -1, st = custom=="{";
5095         var f = Roo.DomQuery.operators[op];
5096         for(var i = 0, ci; ci = cs[i]; i++){
5097             var a;
5098             if(st){
5099                 a = Roo.DomQuery.getStyle(ci, attr);
5100             }
5101             else if(attr == "class" || attr == "className"){
5102                 a = ci.className;
5103             }else if(attr == "for"){
5104                 a = ci.htmlFor;
5105             }else if(attr == "href"){
5106                 a = ci.getAttribute("href", 2);
5107             }else{
5108                 a = ci.getAttribute(attr);
5109             }
5110             if((f && f(a, value)) || (!f && a)){
5111                 r[++ri] = ci;
5112             }
5113         }
5114         return r;
5115     };
5116
5117     function byPseudo(cs, name, value){
5118         return Roo.DomQuery.pseudos[name](cs, value);
5119     };
5120
5121     // This is for IE MSXML which does not support expandos.
5122     // IE runs the same speed using setAttribute, however FF slows way down
5123     // and Safari completely fails so they need to continue to use expandos.
5124     var isIE = window.ActiveXObject ? true : false;
5125
5126     // this eval is stop the compressor from
5127     // renaming the variable to something shorter
5128     
5129     /** eval:var:batch */
5130     var batch = 30803; 
5131
5132     var key = 30803;
5133
5134     function nodupIEXml(cs){
5135         var d = ++key;
5136         cs[0].setAttribute("_nodup", d);
5137         var r = [cs[0]];
5138         for(var i = 1, len = cs.length; i < len; i++){
5139             var c = cs[i];
5140             if(!c.getAttribute("_nodup") != d){
5141                 c.setAttribute("_nodup", d);
5142                 r[r.length] = c;
5143             }
5144         }
5145         for(var i = 0, len = cs.length; i < len; i++){
5146             cs[i].removeAttribute("_nodup");
5147         }
5148         return r;
5149     }
5150
5151     function nodup(cs){
5152         if(!cs){
5153             return [];
5154         }
5155         var len = cs.length, c, i, r = cs, cj, ri = -1;
5156         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5157             return cs;
5158         }
5159         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5160             return nodupIEXml(cs);
5161         }
5162         var d = ++key;
5163         cs[0]._nodup = d;
5164         for(i = 1; c = cs[i]; i++){
5165             if(c._nodup != d){
5166                 c._nodup = d;
5167             }else{
5168                 r = [];
5169                 for(var j = 0; j < i; j++){
5170                     r[++ri] = cs[j];
5171                 }
5172                 for(j = i+1; cj = cs[j]; j++){
5173                     if(cj._nodup != d){
5174                         cj._nodup = d;
5175                         r[++ri] = cj;
5176                     }
5177                 }
5178                 return r;
5179             }
5180         }
5181         return r;
5182     }
5183
5184     function quickDiffIEXml(c1, c2){
5185         var d = ++key;
5186         for(var i = 0, len = c1.length; i < len; i++){
5187             c1[i].setAttribute("_qdiff", d);
5188         }
5189         var r = [];
5190         for(var i = 0, len = c2.length; i < len; i++){
5191             if(c2[i].getAttribute("_qdiff") != d){
5192                 r[r.length] = c2[i];
5193             }
5194         }
5195         for(var i = 0, len = c1.length; i < len; i++){
5196            c1[i].removeAttribute("_qdiff");
5197         }
5198         return r;
5199     }
5200
5201     function quickDiff(c1, c2){
5202         var len1 = c1.length;
5203         if(!len1){
5204             return c2;
5205         }
5206         if(isIE && c1[0].selectSingleNode){
5207             return quickDiffIEXml(c1, c2);
5208         }
5209         var d = ++key;
5210         for(var i = 0; i < len1; i++){
5211             c1[i]._qdiff = d;
5212         }
5213         var r = [];
5214         for(var i = 0, len = c2.length; i < len; i++){
5215             if(c2[i]._qdiff != d){
5216                 r[r.length] = c2[i];
5217             }
5218         }
5219         return r;
5220     }
5221
5222     function quickId(ns, mode, root, id){
5223         if(ns == root){
5224            var d = root.ownerDocument || root;
5225            return d.getElementById(id);
5226         }
5227         ns = getNodes(ns, mode, "*");
5228         return byId(ns, null, id);
5229     }
5230
5231     return {
5232         getStyle : function(el, name){
5233             return Roo.fly(el).getStyle(name);
5234         },
5235         /**
5236          * Compiles a selector/xpath query into a reusable function. The returned function
5237          * takes one parameter "root" (optional), which is the context node from where the query should start.
5238          * @param {String} selector The selector/xpath query
5239          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5240          * @return {Function}
5241          */
5242         compile : function(path, type){
5243             type = type || "select";
5244             
5245             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5246             var q = path, mode, lq;
5247             var tk = Roo.DomQuery.matchers;
5248             var tklen = tk.length;
5249             var mm;
5250
5251             // accept leading mode switch
5252             var lmode = q.match(modeRe);
5253             if(lmode && lmode[1]){
5254                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5255                 q = q.replace(lmode[1], "");
5256             }
5257             // strip leading slashes
5258             while(path.substr(0, 1)=="/"){
5259                 path = path.substr(1);
5260             }
5261
5262             while(q && lq != q){
5263                 lq = q;
5264                 var tm = q.match(tagTokenRe);
5265                 if(type == "select"){
5266                     if(tm){
5267                         if(tm[1] == "#"){
5268                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5269                         }else{
5270                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5271                         }
5272                         q = q.replace(tm[0], "");
5273                     }else if(q.substr(0, 1) != '@'){
5274                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5275                     }
5276                 }else{
5277                     if(tm){
5278                         if(tm[1] == "#"){
5279                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5280                         }else{
5281                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5282                         }
5283                         q = q.replace(tm[0], "");
5284                     }
5285                 }
5286                 while(!(mm = q.match(modeRe))){
5287                     var matched = false;
5288                     for(var j = 0; j < tklen; j++){
5289                         var t = tk[j];
5290                         var m = q.match(t.re);
5291                         if(m){
5292                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5293                                                     return m[i];
5294                                                 });
5295                             q = q.replace(m[0], "");
5296                             matched = true;
5297                             break;
5298                         }
5299                     }
5300                     // prevent infinite loop on bad selector
5301                     if(!matched){
5302                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5303                     }
5304                 }
5305                 if(mm[1]){
5306                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5307                     q = q.replace(mm[1], "");
5308                 }
5309             }
5310             fn[fn.length] = "return nodup(n);\n}";
5311             
5312              /** 
5313               * list of variables that need from compression as they are used by eval.
5314              *  eval:var:batch 
5315              *  eval:var:nodup
5316              *  eval:var:byTag
5317              *  eval:var:ById
5318              *  eval:var:getNodes
5319              *  eval:var:quickId
5320              *  eval:var:mode
5321              *  eval:var:root
5322              *  eval:var:n
5323              *  eval:var:byClassName
5324              *  eval:var:byPseudo
5325              *  eval:var:byAttribute
5326              *  eval:var:attrValue
5327              * 
5328              **/ 
5329             eval(fn.join(""));
5330             return f;
5331         },
5332
5333         /**
5334          * Selects a group of elements.
5335          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5336          * @param {Node} root (optional) The start of the query (defaults to document).
5337          * @return {Array}
5338          */
5339         select : function(path, root, type){
5340             if(!root || root == document){
5341                 root = document;
5342             }
5343             if(typeof root == "string"){
5344                 root = document.getElementById(root);
5345             }
5346             var paths = path.split(",");
5347             var results = [];
5348             for(var i = 0, len = paths.length; i < len; i++){
5349                 var p = paths[i].replace(trimRe, "");
5350                 if(!cache[p]){
5351                     cache[p] = Roo.DomQuery.compile(p);
5352                     if(!cache[p]){
5353                         throw p + " is not a valid selector";
5354                     }
5355                 }
5356                 var result = cache[p](root);
5357                 if(result && result != document){
5358                     results = results.concat(result);
5359                 }
5360             }
5361             if(paths.length > 1){
5362                 return nodup(results);
5363             }
5364             return results;
5365         },
5366
5367         /**
5368          * Selects a single element.
5369          * @param {String} selector The selector/xpath query
5370          * @param {Node} root (optional) The start of the query (defaults to document).
5371          * @return {Element}
5372          */
5373         selectNode : function(path, root){
5374             return Roo.DomQuery.select(path, root)[0];
5375         },
5376
5377         /**
5378          * Selects the value of a node, optionally replacing null with the defaultValue.
5379          * @param {String} selector The selector/xpath query
5380          * @param {Node} root (optional) The start of the query (defaults to document).
5381          * @param {String} defaultValue
5382          */
5383         selectValue : function(path, root, defaultValue){
5384             path = path.replace(trimRe, "");
5385             if(!valueCache[path]){
5386                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5387             }
5388             var n = valueCache[path](root);
5389             n = n[0] ? n[0] : n;
5390             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5391             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5392         },
5393
5394         /**
5395          * Selects the value of a node, parsing integers and floats.
5396          * @param {String} selector The selector/xpath query
5397          * @param {Node} root (optional) The start of the query (defaults to document).
5398          * @param {Number} defaultValue
5399          * @return {Number}
5400          */
5401         selectNumber : function(path, root, defaultValue){
5402             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5403             return parseFloat(v);
5404         },
5405
5406         /**
5407          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5408          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5409          * @param {String} selector The simple selector to test
5410          * @return {Boolean}
5411          */
5412         is : function(el, ss){
5413             if(typeof el == "string"){
5414                 el = document.getElementById(el);
5415             }
5416             var isArray = (el instanceof Array);
5417             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5418             return isArray ? (result.length == el.length) : (result.length > 0);
5419         },
5420
5421         /**
5422          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5423          * @param {Array} el An array of elements to filter
5424          * @param {String} selector The simple selector to test
5425          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5426          * the selector instead of the ones that match
5427          * @return {Array}
5428          */
5429         filter : function(els, ss, nonMatches){
5430             ss = ss.replace(trimRe, "");
5431             if(!simpleCache[ss]){
5432                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5433             }
5434             var result = simpleCache[ss](els);
5435             return nonMatches ? quickDiff(result, els) : result;
5436         },
5437
5438         /**
5439          * Collection of matching regular expressions and code snippets.
5440          */
5441         matchers : [{
5442                 re: /^\.([\w-]+)/,
5443                 select: 'n = byClassName(n, null, " {1} ");'
5444             }, {
5445                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5446                 select: 'n = byPseudo(n, "{1}", "{2}");'
5447             },{
5448                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5449                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5450             }, {
5451                 re: /^#([\w-]+)/,
5452                 select: 'n = byId(n, null, "{1}");'
5453             },{
5454                 re: /^@([\w-]+)/,
5455                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5456             }
5457         ],
5458
5459         /**
5460          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5461          * 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;.
5462          */
5463         operators : {
5464             "=" : function(a, v){
5465                 return a == v;
5466             },
5467             "!=" : function(a, v){
5468                 return a != v;
5469             },
5470             "^=" : function(a, v){
5471                 return a && a.substr(0, v.length) == v;
5472             },
5473             "$=" : function(a, v){
5474                 return a && a.substr(a.length-v.length) == v;
5475             },
5476             "*=" : function(a, v){
5477                 return a && a.indexOf(v) !== -1;
5478             },
5479             "%=" : function(a, v){
5480                 return (a % v) == 0;
5481             },
5482             "|=" : function(a, v){
5483                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5484             },
5485             "~=" : function(a, v){
5486                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5487             }
5488         },
5489
5490         /**
5491          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5492          * and the argument (if any) supplied in the selector.
5493          */
5494         pseudos : {
5495             "first-child" : function(c){
5496                 var r = [], ri = -1, n;
5497                 for(var i = 0, ci; ci = n = c[i]; i++){
5498                     while((n = n.previousSibling) && n.nodeType != 1);
5499                     if(!n){
5500                         r[++ri] = ci;
5501                     }
5502                 }
5503                 return r;
5504             },
5505
5506             "last-child" : function(c){
5507                 var r = [], ri = -1, n;
5508                 for(var i = 0, ci; ci = n = c[i]; i++){
5509                     while((n = n.nextSibling) && n.nodeType != 1);
5510                     if(!n){
5511                         r[++ri] = ci;
5512                     }
5513                 }
5514                 return r;
5515             },
5516
5517             "nth-child" : function(c, a) {
5518                 var r = [], ri = -1;
5519                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5520                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5521                 for(var i = 0, n; n = c[i]; i++){
5522                     var pn = n.parentNode;
5523                     if (batch != pn._batch) {
5524                         var j = 0;
5525                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5526                             if(cn.nodeType == 1){
5527                                cn.nodeIndex = ++j;
5528                             }
5529                         }
5530                         pn._batch = batch;
5531                     }
5532                     if (f == 1) {
5533                         if (l == 0 || n.nodeIndex == l){
5534                             r[++ri] = n;
5535                         }
5536                     } else if ((n.nodeIndex + l) % f == 0){
5537                         r[++ri] = n;
5538                     }
5539                 }
5540
5541                 return r;
5542             },
5543
5544             "only-child" : function(c){
5545                 var r = [], ri = -1;;
5546                 for(var i = 0, ci; ci = c[i]; i++){
5547                     if(!prev(ci) && !next(ci)){
5548                         r[++ri] = ci;
5549                     }
5550                 }
5551                 return r;
5552             },
5553
5554             "empty" : function(c){
5555                 var r = [], ri = -1;
5556                 for(var i = 0, ci; ci = c[i]; i++){
5557                     var cns = ci.childNodes, j = 0, cn, empty = true;
5558                     while(cn = cns[j]){
5559                         ++j;
5560                         if(cn.nodeType == 1 || cn.nodeType == 3){
5561                             empty = false;
5562                             break;
5563                         }
5564                     }
5565                     if(empty){
5566                         r[++ri] = ci;
5567                     }
5568                 }
5569                 return r;
5570             },
5571
5572             "contains" : function(c, v){
5573                 var r = [], ri = -1;
5574                 for(var i = 0, ci; ci = c[i]; i++){
5575                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5576                         r[++ri] = ci;
5577                     }
5578                 }
5579                 return r;
5580             },
5581
5582             "nodeValue" : function(c, v){
5583                 var r = [], ri = -1;
5584                 for(var i = 0, ci; ci = c[i]; i++){
5585                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5586                         r[++ri] = ci;
5587                     }
5588                 }
5589                 return r;
5590             },
5591
5592             "checked" : function(c){
5593                 var r = [], ri = -1;
5594                 for(var i = 0, ci; ci = c[i]; i++){
5595                     if(ci.checked == true){
5596                         r[++ri] = ci;
5597                     }
5598                 }
5599                 return r;
5600             },
5601
5602             "not" : function(c, ss){
5603                 return Roo.DomQuery.filter(c, ss, true);
5604             },
5605
5606             "odd" : function(c){
5607                 return this["nth-child"](c, "odd");
5608             },
5609
5610             "even" : function(c){
5611                 return this["nth-child"](c, "even");
5612             },
5613
5614             "nth" : function(c, a){
5615                 return c[a-1] || [];
5616             },
5617
5618             "first" : function(c){
5619                 return c[0] || [];
5620             },
5621
5622             "last" : function(c){
5623                 return c[c.length-1] || [];
5624             },
5625
5626             "has" : function(c, ss){
5627                 var s = Roo.DomQuery.select;
5628                 var r = [], ri = -1;
5629                 for(var i = 0, ci; ci = c[i]; i++){
5630                     if(s(ss, ci).length > 0){
5631                         r[++ri] = ci;
5632                     }
5633                 }
5634                 return r;
5635             },
5636
5637             "next" : function(c, ss){
5638                 var is = Roo.DomQuery.is;
5639                 var r = [], ri = -1;
5640                 for(var i = 0, ci; ci = c[i]; i++){
5641                     var n = next(ci);
5642                     if(n && is(n, ss)){
5643                         r[++ri] = ci;
5644                     }
5645                 }
5646                 return r;
5647             },
5648
5649             "prev" : function(c, ss){
5650                 var is = Roo.DomQuery.is;
5651                 var r = [], ri = -1;
5652                 for(var i = 0, ci; ci = c[i]; i++){
5653                     var n = prev(ci);
5654                     if(n && is(n, ss)){
5655                         r[++ri] = ci;
5656                     }
5657                 }
5658                 return r;
5659             }
5660         }
5661     };
5662 }();
5663
5664 /**
5665  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5666  * @param {String} path The selector/xpath query
5667  * @param {Node} root (optional) The start of the query (defaults to document).
5668  * @return {Array}
5669  * @member Roo
5670  * @method query
5671  */
5672 Roo.query = Roo.DomQuery.select;
5673 /*
5674  * Based on:
5675  * Ext JS Library 1.1.1
5676  * Copyright(c) 2006-2007, Ext JS, LLC.
5677  *
5678  * Originally Released Under LGPL - original licence link has changed is not relivant.
5679  *
5680  * Fork - LGPL
5681  * <script type="text/javascript">
5682  */
5683
5684 /**
5685  * @class Roo.util.Observable
5686  * Base class that provides a common interface for publishing events. Subclasses are expected to
5687  * to have a property "events" with all the events defined.<br>
5688  * For example:
5689  * <pre><code>
5690  Employee = function(name){
5691     this.name = name;
5692     this.addEvents({
5693         "fired" : true,
5694         "quit" : true
5695     });
5696  }
5697  Roo.extend(Employee, Roo.util.Observable);
5698 </code></pre>
5699  * @param {Object} config properties to use (incuding events / listeners)
5700  */
5701
5702 Roo.util.Observable = function(cfg){
5703     
5704     cfg = cfg|| {};
5705     this.addEvents(cfg.events || {});
5706     if (cfg.events) {
5707         delete cfg.events; // make sure
5708     }
5709      
5710     Roo.apply(this, cfg);
5711     
5712     if(this.listeners){
5713         this.on(this.listeners);
5714         delete this.listeners;
5715     }
5716 };
5717 Roo.util.Observable.prototype = {
5718     /** 
5719  * @cfg {Object} listeners  list of events and functions to call for this object, 
5720  * For example :
5721  * <pre><code>
5722     listeners :  { 
5723        'click' : function(e) {
5724            ..... 
5725         } ,
5726         .... 
5727     } 
5728   </code></pre>
5729  */
5730     
5731     
5732     /**
5733      * Fires the specified event with the passed parameters (minus the event name).
5734      * @param {String} eventName
5735      * @param {Object...} args Variable number of parameters are passed to handlers
5736      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5737      */
5738     fireEvent : function(){
5739         var ce = this.events[arguments[0].toLowerCase()];
5740         if(typeof ce == "object"){
5741             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5742         }else{
5743             return true;
5744         }
5745     },
5746
5747     // private
5748     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5749
5750     /**
5751      * Appends an event handler to this component
5752      * @param {String}   eventName The type of event to listen for
5753      * @param {Function} handler The method the event invokes
5754      * @param {Object}   scope (optional) The scope in which to execute the handler
5755      * function. The handler function's "this" context.
5756      * @param {Object}   options (optional) An object containing handler configuration
5757      * properties. This may contain any of the following properties:<ul>
5758      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5759      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5760      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5761      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5762      * by the specified number of milliseconds. If the event fires again within that time, the original
5763      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5764      * </ul><br>
5765      * <p>
5766      * <b>Combining Options</b><br>
5767      * Using the options argument, it is possible to combine different types of listeners:<br>
5768      * <br>
5769      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5770                 <pre><code>
5771                 el.on('click', this.onClick, this, {
5772                         single: true,
5773                 delay: 100,
5774                 forumId: 4
5775                 });
5776                 </code></pre>
5777      * <p>
5778      * <b>Attaching multiple handlers in 1 call</b><br>
5779      * The method also allows for a single argument to be passed which is a config object containing properties
5780      * which specify multiple handlers.
5781      * <pre><code>
5782                 el.on({
5783                         'click': {
5784                         fn: this.onClick,
5785                         scope: this,
5786                         delay: 100
5787                 }, 
5788                 'mouseover': {
5789                         fn: this.onMouseOver,
5790                         scope: this
5791                 },
5792                 'mouseout': {
5793                         fn: this.onMouseOut,
5794                         scope: this
5795                 }
5796                 });
5797                 </code></pre>
5798      * <p>
5799      * Or a shorthand syntax which passes the same scope object to all handlers:
5800         <pre><code>
5801                 el.on({
5802                         'click': this.onClick,
5803                 'mouseover': this.onMouseOver,
5804                 'mouseout': this.onMouseOut,
5805                 scope: this
5806                 });
5807                 </code></pre>
5808      */
5809     addListener : function(eventName, fn, scope, o){
5810         if(typeof eventName == "object"){
5811             o = eventName;
5812             for(var e in o){
5813                 if(this.filterOptRe.test(e)){
5814                     continue;
5815                 }
5816                 if(typeof o[e] == "function"){
5817                     // shared options
5818                     this.addListener(e, o[e], o.scope,  o);
5819                 }else{
5820                     // individual options
5821                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5822                 }
5823             }
5824             return;
5825         }
5826         o = (!o || typeof o == "boolean") ? {} : o;
5827         eventName = eventName.toLowerCase();
5828         var ce = this.events[eventName] || true;
5829         if(typeof ce == "boolean"){
5830             ce = new Roo.util.Event(this, eventName);
5831             this.events[eventName] = ce;
5832         }
5833         ce.addListener(fn, scope, o);
5834     },
5835
5836     /**
5837      * Removes a listener
5838      * @param {String}   eventName     The type of event to listen for
5839      * @param {Function} handler        The handler to remove
5840      * @param {Object}   scope  (optional) The scope (this object) for the handler
5841      */
5842     removeListener : function(eventName, fn, scope){
5843         var ce = this.events[eventName.toLowerCase()];
5844         if(typeof ce == "object"){
5845             ce.removeListener(fn, scope);
5846         }
5847     },
5848
5849     /**
5850      * Removes all listeners for this object
5851      */
5852     purgeListeners : function(){
5853         for(var evt in this.events){
5854             if(typeof this.events[evt] == "object"){
5855                  this.events[evt].clearListeners();
5856             }
5857         }
5858     },
5859
5860     relayEvents : function(o, events){
5861         var createHandler = function(ename){
5862             return function(){
5863                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5864             };
5865         };
5866         for(var i = 0, len = events.length; i < len; i++){
5867             var ename = events[i];
5868             if(!this.events[ename]){ this.events[ename] = true; };
5869             o.on(ename, createHandler(ename), this);
5870         }
5871     },
5872
5873     /**
5874      * Used to define events on this Observable
5875      * @param {Object} object The object with the events defined
5876      */
5877     addEvents : function(o){
5878         if(!this.events){
5879             this.events = {};
5880         }
5881         Roo.applyIf(this.events, o);
5882     },
5883
5884     /**
5885      * Checks to see if this object has any listeners for a specified event
5886      * @param {String} eventName The name of the event to check for
5887      * @return {Boolean} True if the event is being listened for, else false
5888      */
5889     hasListener : function(eventName){
5890         var e = this.events[eventName];
5891         return typeof e == "object" && e.listeners.length > 0;
5892     }
5893 };
5894 /**
5895  * Appends an event handler to this element (shorthand for addListener)
5896  * @param {String}   eventName     The type of event to listen for
5897  * @param {Function} handler        The method the event invokes
5898  * @param {Object}   scope (optional) The scope in which to execute the handler
5899  * function. The handler function's "this" context.
5900  * @param {Object}   options  (optional)
5901  * @method
5902  */
5903 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5904 /**
5905  * Removes a listener (shorthand for removeListener)
5906  * @param {String}   eventName     The type of event to listen for
5907  * @param {Function} handler        The handler to remove
5908  * @param {Object}   scope  (optional) The scope (this object) for the handler
5909  * @method
5910  */
5911 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5912
5913 /**
5914  * Starts capture on the specified Observable. All events will be passed
5915  * to the supplied function with the event name + standard signature of the event
5916  * <b>before</b> the event is fired. If the supplied function returns false,
5917  * the event will not fire.
5918  * @param {Observable} o The Observable to capture
5919  * @param {Function} fn The function to call
5920  * @param {Object} scope (optional) The scope (this object) for the fn
5921  * @static
5922  */
5923 Roo.util.Observable.capture = function(o, fn, scope){
5924     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5925 };
5926
5927 /**
5928  * Removes <b>all</b> added captures from the Observable.
5929  * @param {Observable} o The Observable to release
5930  * @static
5931  */
5932 Roo.util.Observable.releaseCapture = function(o){
5933     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5934 };
5935
5936 (function(){
5937
5938     var createBuffered = function(h, o, scope){
5939         var task = new Roo.util.DelayedTask();
5940         return function(){
5941             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5942         };
5943     };
5944
5945     var createSingle = function(h, e, fn, scope){
5946         return function(){
5947             e.removeListener(fn, scope);
5948             return h.apply(scope, arguments);
5949         };
5950     };
5951
5952     var createDelayed = function(h, o, scope){
5953         return function(){
5954             var args = Array.prototype.slice.call(arguments, 0);
5955             setTimeout(function(){
5956                 h.apply(scope, args);
5957             }, o.delay || 10);
5958         };
5959     };
5960
5961     Roo.util.Event = function(obj, name){
5962         this.name = name;
5963         this.obj = obj;
5964         this.listeners = [];
5965     };
5966
5967     Roo.util.Event.prototype = {
5968         addListener : function(fn, scope, options){
5969             var o = options || {};
5970             scope = scope || this.obj;
5971             if(!this.isListening(fn, scope)){
5972                 var l = {fn: fn, scope: scope, options: o};
5973                 var h = fn;
5974                 if(o.delay){
5975                     h = createDelayed(h, o, scope);
5976                 }
5977                 if(o.single){
5978                     h = createSingle(h, this, fn, scope);
5979                 }
5980                 if(o.buffer){
5981                     h = createBuffered(h, o, scope);
5982                 }
5983                 l.fireFn = h;
5984                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5985                     this.listeners.push(l);
5986                 }else{
5987                     this.listeners = this.listeners.slice(0);
5988                     this.listeners.push(l);
5989                 }
5990             }
5991         },
5992
5993         findListener : function(fn, scope){
5994             scope = scope || this.obj;
5995             var ls = this.listeners;
5996             for(var i = 0, len = ls.length; i < len; i++){
5997                 var l = ls[i];
5998                 if(l.fn == fn && l.scope == scope){
5999                     return i;
6000                 }
6001             }
6002             return -1;
6003         },
6004
6005         isListening : function(fn, scope){
6006             return this.findListener(fn, scope) != -1;
6007         },
6008
6009         removeListener : function(fn, scope){
6010             var index;
6011             if((index = this.findListener(fn, scope)) != -1){
6012                 if(!this.firing){
6013                     this.listeners.splice(index, 1);
6014                 }else{
6015                     this.listeners = this.listeners.slice(0);
6016                     this.listeners.splice(index, 1);
6017                 }
6018                 return true;
6019             }
6020             return false;
6021         },
6022
6023         clearListeners : function(){
6024             this.listeners = [];
6025         },
6026
6027         fire : function(){
6028             var ls = this.listeners, scope, len = ls.length;
6029             if(len > 0){
6030                 this.firing = true;
6031                 var args = Array.prototype.slice.call(arguments, 0);
6032                 for(var i = 0; i < len; i++){
6033                     var l = ls[i];
6034                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6035                         this.firing = false;
6036                         return false;
6037                     }
6038                 }
6039                 this.firing = false;
6040             }
6041             return true;
6042         }
6043     };
6044 })();/*
6045  * Based on:
6046  * Ext JS Library 1.1.1
6047  * Copyright(c) 2006-2007, Ext JS, LLC.
6048  *
6049  * Originally Released Under LGPL - original licence link has changed is not relivant.
6050  *
6051  * Fork - LGPL
6052  * <script type="text/javascript">
6053  */
6054
6055 /**
6056  * @class Roo.EventManager
6057  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6058  * several useful events directly.
6059  * See {@link Roo.EventObject} for more details on normalized event objects.
6060  * @singleton
6061  */
6062 Roo.EventManager = function(){
6063     var docReadyEvent, docReadyProcId, docReadyState = false;
6064     var resizeEvent, resizeTask, textEvent, textSize;
6065     var E = Roo.lib.Event;
6066     var D = Roo.lib.Dom;
6067
6068     
6069     
6070
6071     var fireDocReady = function(){
6072         if(!docReadyState){
6073             docReadyState = true;
6074             Roo.isReady = true;
6075             if(docReadyProcId){
6076                 clearInterval(docReadyProcId);
6077             }
6078             if(Roo.isGecko || Roo.isOpera) {
6079                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6080             }
6081             if(Roo.isIE){
6082                 var defer = document.getElementById("ie-deferred-loader");
6083                 if(defer){
6084                     defer.onreadystatechange = null;
6085                     defer.parentNode.removeChild(defer);
6086                 }
6087             }
6088             if(docReadyEvent){
6089                 docReadyEvent.fire();
6090                 docReadyEvent.clearListeners();
6091             }
6092         }
6093     };
6094     
6095     var initDocReady = function(){
6096         docReadyEvent = new Roo.util.Event();
6097         if(Roo.isGecko || Roo.isOpera) {
6098             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6099         }else if(Roo.isIE){
6100             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6101             var defer = document.getElementById("ie-deferred-loader");
6102             defer.onreadystatechange = function(){
6103                 if(this.readyState == "complete"){
6104                     fireDocReady();
6105                 }
6106             };
6107         }else if(Roo.isSafari){ 
6108             docReadyProcId = setInterval(function(){
6109                 var rs = document.readyState;
6110                 if(rs == "complete") {
6111                     fireDocReady();     
6112                  }
6113             }, 10);
6114         }
6115         // no matter what, make sure it fires on load
6116         E.on(window, "load", fireDocReady);
6117     };
6118
6119     var createBuffered = function(h, o){
6120         var task = new Roo.util.DelayedTask(h);
6121         return function(e){
6122             // create new event object impl so new events don't wipe out properties
6123             e = new Roo.EventObjectImpl(e);
6124             task.delay(o.buffer, h, null, [e]);
6125         };
6126     };
6127
6128     var createSingle = function(h, el, ename, fn){
6129         return function(e){
6130             Roo.EventManager.removeListener(el, ename, fn);
6131             h(e);
6132         };
6133     };
6134
6135     var createDelayed = function(h, o){
6136         return function(e){
6137             // create new event object impl so new events don't wipe out properties
6138             e = new Roo.EventObjectImpl(e);
6139             setTimeout(function(){
6140                 h(e);
6141             }, o.delay || 10);
6142         };
6143     };
6144     var transitionEndVal = false;
6145     
6146     var transitionEnd = function()
6147     {
6148         if (transitionEndVal) {
6149             return transitionEndVal;
6150         }
6151         var el = document.createElement('div');
6152
6153         var transEndEventNames = {
6154             WebkitTransition : 'webkitTransitionEnd',
6155             MozTransition    : 'transitionend',
6156             OTransition      : 'oTransitionEnd otransitionend',
6157             transition       : 'transitionend'
6158         };
6159     
6160         for (var name in transEndEventNames) {
6161             if (el.style[name] !== undefined) {
6162                 transitionEndVal = transEndEventNames[name];
6163                 return  transitionEndVal ;
6164             }
6165         }
6166     }
6167     
6168
6169     var listen = function(element, ename, opt, fn, scope){
6170         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6171         fn = fn || o.fn; scope = scope || o.scope;
6172         var el = Roo.getDom(element);
6173         
6174         
6175         if(!el){
6176             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6177         }
6178         
6179         if (ename == 'transitionend') {
6180             ename = transitionEnd();
6181         }
6182         var h = function(e){
6183             e = Roo.EventObject.setEvent(e);
6184             var t;
6185             if(o.delegate){
6186                 t = e.getTarget(o.delegate, el);
6187                 if(!t){
6188                     return;
6189                 }
6190             }else{
6191                 t = e.target;
6192             }
6193             if(o.stopEvent === true){
6194                 e.stopEvent();
6195             }
6196             if(o.preventDefault === true){
6197                e.preventDefault();
6198             }
6199             if(o.stopPropagation === true){
6200                 e.stopPropagation();
6201             }
6202
6203             if(o.normalized === false){
6204                 e = e.browserEvent;
6205             }
6206
6207             fn.call(scope || el, e, t, o);
6208         };
6209         if(o.delay){
6210             h = createDelayed(h, o);
6211         }
6212         if(o.single){
6213             h = createSingle(h, el, ename, fn);
6214         }
6215         if(o.buffer){
6216             h = createBuffered(h, o);
6217         }
6218         fn._handlers = fn._handlers || [];
6219         
6220         
6221         fn._handlers.push([Roo.id(el), ename, h]);
6222         
6223         
6224          
6225         E.on(el, ename, h);
6226         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6227             el.addEventListener("DOMMouseScroll", h, false);
6228             E.on(window, 'unload', function(){
6229                 el.removeEventListener("DOMMouseScroll", h, false);
6230             });
6231         }
6232         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6233             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6234         }
6235         return h;
6236     };
6237
6238     var stopListening = function(el, ename, fn){
6239         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6240         if(hds){
6241             for(var i = 0, len = hds.length; i < len; i++){
6242                 var h = hds[i];
6243                 if(h[0] == id && h[1] == ename){
6244                     hd = h[2];
6245                     hds.splice(i, 1);
6246                     break;
6247                 }
6248             }
6249         }
6250         E.un(el, ename, hd);
6251         el = Roo.getDom(el);
6252         if(ename == "mousewheel" && el.addEventListener){
6253             el.removeEventListener("DOMMouseScroll", hd, false);
6254         }
6255         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6256             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6257         }
6258     };
6259
6260     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6261     
6262     var pub = {
6263         
6264         
6265         /** 
6266          * Fix for doc tools
6267          * @scope Roo.EventManager
6268          */
6269         
6270         
6271         /** 
6272          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6273          * object with a Roo.EventObject
6274          * @param {Function} fn        The method the event invokes
6275          * @param {Object}   scope    An object that becomes the scope of the handler
6276          * @param {boolean}  override If true, the obj passed in becomes
6277          *                             the execution scope of the listener
6278          * @return {Function} The wrapped function
6279          * @deprecated
6280          */
6281         wrap : function(fn, scope, override){
6282             return function(e){
6283                 Roo.EventObject.setEvent(e);
6284                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6285             };
6286         },
6287         
6288         /**
6289      * Appends an event handler to an element (shorthand for addListener)
6290      * @param {String/HTMLElement}   element        The html element or id to assign the
6291      * @param {String}   eventName The type of event to listen for
6292      * @param {Function} handler The method the event invokes
6293      * @param {Object}   scope (optional) The scope in which to execute the handler
6294      * function. The handler function's "this" context.
6295      * @param {Object}   options (optional) An object containing handler configuration
6296      * properties. This may contain any of the following properties:<ul>
6297      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6298      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6299      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6300      * <li>preventDefault {Boolean} True to prevent the default action</li>
6301      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6302      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6303      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6304      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6305      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6306      * by the specified number of milliseconds. If the event fires again within that time, the original
6307      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6308      * </ul><br>
6309      * <p>
6310      * <b>Combining Options</b><br>
6311      * Using the options argument, it is possible to combine different types of listeners:<br>
6312      * <br>
6313      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6314      * Code:<pre><code>
6315 el.on('click', this.onClick, this, {
6316     single: true,
6317     delay: 100,
6318     stopEvent : true,
6319     forumId: 4
6320 });</code></pre>
6321      * <p>
6322      * <b>Attaching multiple handlers in 1 call</b><br>
6323       * The method also allows for a single argument to be passed which is a config object containing properties
6324      * which specify multiple handlers.
6325      * <p>
6326      * Code:<pre><code>
6327 el.on({
6328     'click' : {
6329         fn: this.onClick
6330         scope: this,
6331         delay: 100
6332     },
6333     'mouseover' : {
6334         fn: this.onMouseOver
6335         scope: this
6336     },
6337     'mouseout' : {
6338         fn: this.onMouseOut
6339         scope: this
6340     }
6341 });</code></pre>
6342      * <p>
6343      * Or a shorthand syntax:<br>
6344      * Code:<pre><code>
6345 el.on({
6346     'click' : this.onClick,
6347     'mouseover' : this.onMouseOver,
6348     'mouseout' : this.onMouseOut
6349     scope: this
6350 });</code></pre>
6351      */
6352         addListener : function(element, eventName, fn, scope, options){
6353             if(typeof eventName == "object"){
6354                 var o = eventName;
6355                 for(var e in o){
6356                     if(propRe.test(e)){
6357                         continue;
6358                     }
6359                     if(typeof o[e] == "function"){
6360                         // shared options
6361                         listen(element, e, o, o[e], o.scope);
6362                     }else{
6363                         // individual options
6364                         listen(element, e, o[e]);
6365                     }
6366                 }
6367                 return;
6368             }
6369             return listen(element, eventName, options, fn, scope);
6370         },
6371         
6372         /**
6373          * Removes an event handler
6374          *
6375          * @param {String/HTMLElement}   element        The id or html element to remove the 
6376          *                             event from
6377          * @param {String}   eventName     The type of event
6378          * @param {Function} fn
6379          * @return {Boolean} True if a listener was actually removed
6380          */
6381         removeListener : function(element, eventName, fn){
6382             return stopListening(element, eventName, fn);
6383         },
6384         
6385         /**
6386          * Fires when the document is ready (before onload and before images are loaded). Can be 
6387          * accessed shorthanded Roo.onReady().
6388          * @param {Function} fn        The method the event invokes
6389          * @param {Object}   scope    An  object that becomes the scope of the handler
6390          * @param {boolean}  options
6391          */
6392         onDocumentReady : function(fn, scope, options){
6393             if(docReadyState){ // if it already fired
6394                 docReadyEvent.addListener(fn, scope, options);
6395                 docReadyEvent.fire();
6396                 docReadyEvent.clearListeners();
6397                 return;
6398             }
6399             if(!docReadyEvent){
6400                 initDocReady();
6401             }
6402             docReadyEvent.addListener(fn, scope, options);
6403         },
6404         
6405         /**
6406          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6407          * @param {Function} fn        The method the event invokes
6408          * @param {Object}   scope    An object that becomes the scope of the handler
6409          * @param {boolean}  options
6410          */
6411         onWindowResize : function(fn, scope, options){
6412             if(!resizeEvent){
6413                 resizeEvent = new Roo.util.Event();
6414                 resizeTask = new Roo.util.DelayedTask(function(){
6415                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6416                 });
6417                 E.on(window, "resize", function(){
6418                     if(Roo.isIE){
6419                         resizeTask.delay(50);
6420                     }else{
6421                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6422                     }
6423                 });
6424             }
6425             resizeEvent.addListener(fn, scope, options);
6426         },
6427
6428         /**
6429          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6430          * @param {Function} fn        The method the event invokes
6431          * @param {Object}   scope    An object that becomes the scope of the handler
6432          * @param {boolean}  options
6433          */
6434         onTextResize : function(fn, scope, options){
6435             if(!textEvent){
6436                 textEvent = new Roo.util.Event();
6437                 var textEl = new Roo.Element(document.createElement('div'));
6438                 textEl.dom.className = 'x-text-resize';
6439                 textEl.dom.innerHTML = 'X';
6440                 textEl.appendTo(document.body);
6441                 textSize = textEl.dom.offsetHeight;
6442                 setInterval(function(){
6443                     if(textEl.dom.offsetHeight != textSize){
6444                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6445                     }
6446                 }, this.textResizeInterval);
6447             }
6448             textEvent.addListener(fn, scope, options);
6449         },
6450
6451         /**
6452          * Removes the passed window resize listener.
6453          * @param {Function} fn        The method the event invokes
6454          * @param {Object}   scope    The scope of handler
6455          */
6456         removeResizeListener : function(fn, scope){
6457             if(resizeEvent){
6458                 resizeEvent.removeListener(fn, scope);
6459             }
6460         },
6461
6462         // private
6463         fireResize : function(){
6464             if(resizeEvent){
6465                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6466             }   
6467         },
6468         /**
6469          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6470          */
6471         ieDeferSrc : false,
6472         /**
6473          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6474          */
6475         textResizeInterval : 50
6476     };
6477     
6478     /**
6479      * Fix for doc tools
6480      * @scopeAlias pub=Roo.EventManager
6481      */
6482     
6483      /**
6484      * Appends an event handler to an element (shorthand for addListener)
6485      * @param {String/HTMLElement}   element        The html element or id to assign the
6486      * @param {String}   eventName The type of event to listen for
6487      * @param {Function} handler The method the event invokes
6488      * @param {Object}   scope (optional) The scope in which to execute the handler
6489      * function. The handler function's "this" context.
6490      * @param {Object}   options (optional) An object containing handler configuration
6491      * properties. This may contain any of the following properties:<ul>
6492      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6493      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6494      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6495      * <li>preventDefault {Boolean} True to prevent the default action</li>
6496      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6497      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6498      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6499      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6500      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6501      * by the specified number of milliseconds. If the event fires again within that time, the original
6502      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6503      * </ul><br>
6504      * <p>
6505      * <b>Combining Options</b><br>
6506      * Using the options argument, it is possible to combine different types of listeners:<br>
6507      * <br>
6508      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6509      * Code:<pre><code>
6510 el.on('click', this.onClick, this, {
6511     single: true,
6512     delay: 100,
6513     stopEvent : true,
6514     forumId: 4
6515 });</code></pre>
6516      * <p>
6517      * <b>Attaching multiple handlers in 1 call</b><br>
6518       * The method also allows for a single argument to be passed which is a config object containing properties
6519      * which specify multiple handlers.
6520      * <p>
6521      * Code:<pre><code>
6522 el.on({
6523     'click' : {
6524         fn: this.onClick
6525         scope: this,
6526         delay: 100
6527     },
6528     'mouseover' : {
6529         fn: this.onMouseOver
6530         scope: this
6531     },
6532     'mouseout' : {
6533         fn: this.onMouseOut
6534         scope: this
6535     }
6536 });</code></pre>
6537      * <p>
6538      * Or a shorthand syntax:<br>
6539      * Code:<pre><code>
6540 el.on({
6541     'click' : this.onClick,
6542     'mouseover' : this.onMouseOver,
6543     'mouseout' : this.onMouseOut
6544     scope: this
6545 });</code></pre>
6546      */
6547     pub.on = pub.addListener;
6548     pub.un = pub.removeListener;
6549
6550     pub.stoppedMouseDownEvent = new Roo.util.Event();
6551     return pub;
6552 }();
6553 /**
6554   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6555   * @param {Function} fn        The method the event invokes
6556   * @param {Object}   scope    An  object that becomes the scope of the handler
6557   * @param {boolean}  override If true, the obj passed in becomes
6558   *                             the execution scope of the listener
6559   * @member Roo
6560   * @method onReady
6561  */
6562 Roo.onReady = Roo.EventManager.onDocumentReady;
6563
6564 Roo.onReady(function(){
6565     var bd = Roo.get(document.body);
6566     if(!bd){ return; }
6567
6568     var cls = [
6569             Roo.isIE ? "roo-ie"
6570             : Roo.isGecko ? "roo-gecko"
6571             : Roo.isOpera ? "roo-opera"
6572             : Roo.isSafari ? "roo-safari" : ""];
6573
6574     if(Roo.isMac){
6575         cls.push("roo-mac");
6576     }
6577     if(Roo.isLinux){
6578         cls.push("roo-linux");
6579     }
6580     if(Roo.isIOS){
6581         cls.push("roo-ios");
6582     }
6583     if(Roo.isBorderBox){
6584         cls.push('roo-border-box');
6585     }
6586     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6587         var p = bd.dom.parentNode;
6588         if(p){
6589             p.className += ' roo-strict';
6590         }
6591     }
6592     bd.addClass(cls.join(' '));
6593 });
6594
6595 /**
6596  * @class Roo.EventObject
6597  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6598  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6599  * Example:
6600  * <pre><code>
6601  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6602     e.preventDefault();
6603     var target = e.getTarget();
6604     ...
6605  }
6606  var myDiv = Roo.get("myDiv");
6607  myDiv.on("click", handleClick);
6608  //or
6609  Roo.EventManager.on("myDiv", 'click', handleClick);
6610  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6611  </code></pre>
6612  * @singleton
6613  */
6614 Roo.EventObject = function(){
6615     
6616     var E = Roo.lib.Event;
6617     
6618     // safari keypress events for special keys return bad keycodes
6619     var safariKeys = {
6620         63234 : 37, // left
6621         63235 : 39, // right
6622         63232 : 38, // up
6623         63233 : 40, // down
6624         63276 : 33, // page up
6625         63277 : 34, // page down
6626         63272 : 46, // delete
6627         63273 : 36, // home
6628         63275 : 35  // end
6629     };
6630
6631     // normalize button clicks
6632     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6633                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6634
6635     Roo.EventObjectImpl = function(e){
6636         if(e){
6637             this.setEvent(e.browserEvent || e);
6638         }
6639     };
6640     Roo.EventObjectImpl.prototype = {
6641         /**
6642          * Used to fix doc tools.
6643          * @scope Roo.EventObject.prototype
6644          */
6645             
6646
6647         
6648         
6649         /** The normal browser event */
6650         browserEvent : null,
6651         /** The button pressed in a mouse event */
6652         button : -1,
6653         /** True if the shift key was down during the event */
6654         shiftKey : false,
6655         /** True if the control key was down during the event */
6656         ctrlKey : false,
6657         /** True if the alt key was down during the event */
6658         altKey : false,
6659
6660         /** Key constant 
6661         * @type Number */
6662         BACKSPACE : 8,
6663         /** Key constant 
6664         * @type Number */
6665         TAB : 9,
6666         /** Key constant 
6667         * @type Number */
6668         RETURN : 13,
6669         /** Key constant 
6670         * @type Number */
6671         ENTER : 13,
6672         /** Key constant 
6673         * @type Number */
6674         SHIFT : 16,
6675         /** Key constant 
6676         * @type Number */
6677         CONTROL : 17,
6678         /** Key constant 
6679         * @type Number */
6680         ESC : 27,
6681         /** Key constant 
6682         * @type Number */
6683         SPACE : 32,
6684         /** Key constant 
6685         * @type Number */
6686         PAGEUP : 33,
6687         /** Key constant 
6688         * @type Number */
6689         PAGEDOWN : 34,
6690         /** Key constant 
6691         * @type Number */
6692         END : 35,
6693         /** Key constant 
6694         * @type Number */
6695         HOME : 36,
6696         /** Key constant 
6697         * @type Number */
6698         LEFT : 37,
6699         /** Key constant 
6700         * @type Number */
6701         UP : 38,
6702         /** Key constant 
6703         * @type Number */
6704         RIGHT : 39,
6705         /** Key constant 
6706         * @type Number */
6707         DOWN : 40,
6708         /** Key constant 
6709         * @type Number */
6710         DELETE : 46,
6711         /** Key constant 
6712         * @type Number */
6713         F5 : 116,
6714
6715            /** @private */
6716         setEvent : function(e){
6717             if(e == this || (e && e.browserEvent)){ // already wrapped
6718                 return e;
6719             }
6720             this.browserEvent = e;
6721             if(e){
6722                 // normalize buttons
6723                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6724                 if(e.type == 'click' && this.button == -1){
6725                     this.button = 0;
6726                 }
6727                 this.type = e.type;
6728                 this.shiftKey = e.shiftKey;
6729                 // mac metaKey behaves like ctrlKey
6730                 this.ctrlKey = e.ctrlKey || e.metaKey;
6731                 this.altKey = e.altKey;
6732                 // in getKey these will be normalized for the mac
6733                 this.keyCode = e.keyCode;
6734                 // keyup warnings on firefox.
6735                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6736                 // cache the target for the delayed and or buffered events
6737                 this.target = E.getTarget(e);
6738                 // same for XY
6739                 this.xy = E.getXY(e);
6740             }else{
6741                 this.button = -1;
6742                 this.shiftKey = false;
6743                 this.ctrlKey = false;
6744                 this.altKey = false;
6745                 this.keyCode = 0;
6746                 this.charCode =0;
6747                 this.target = null;
6748                 this.xy = [0, 0];
6749             }
6750             return this;
6751         },
6752
6753         /**
6754          * Stop the event (preventDefault and stopPropagation)
6755          */
6756         stopEvent : function(){
6757             if(this.browserEvent){
6758                 if(this.browserEvent.type == 'mousedown'){
6759                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6760                 }
6761                 E.stopEvent(this.browserEvent);
6762             }
6763         },
6764
6765         /**
6766          * Prevents the browsers default handling of the event.
6767          */
6768         preventDefault : function(){
6769             if(this.browserEvent){
6770                 E.preventDefault(this.browserEvent);
6771             }
6772         },
6773
6774         /** @private */
6775         isNavKeyPress : function(){
6776             var k = this.keyCode;
6777             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6778             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6779         },
6780
6781         isSpecialKey : function(){
6782             var k = this.keyCode;
6783             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6784             (k == 16) || (k == 17) ||
6785             (k >= 18 && k <= 20) ||
6786             (k >= 33 && k <= 35) ||
6787             (k >= 36 && k <= 39) ||
6788             (k >= 44 && k <= 45);
6789         },
6790         /**
6791          * Cancels bubbling of the event.
6792          */
6793         stopPropagation : function(){
6794             if(this.browserEvent){
6795                 if(this.type == 'mousedown'){
6796                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6797                 }
6798                 E.stopPropagation(this.browserEvent);
6799             }
6800         },
6801
6802         /**
6803          * Gets the key code for the event.
6804          * @return {Number}
6805          */
6806         getCharCode : function(){
6807             return this.charCode || this.keyCode;
6808         },
6809
6810         /**
6811          * Returns a normalized keyCode for the event.
6812          * @return {Number} The key code
6813          */
6814         getKey : function(){
6815             var k = this.keyCode || this.charCode;
6816             return Roo.isSafari ? (safariKeys[k] || k) : k;
6817         },
6818
6819         /**
6820          * Gets the x coordinate of the event.
6821          * @return {Number}
6822          */
6823         getPageX : function(){
6824             return this.xy[0];
6825         },
6826
6827         /**
6828          * Gets the y coordinate of the event.
6829          * @return {Number}
6830          */
6831         getPageY : function(){
6832             return this.xy[1];
6833         },
6834
6835         /**
6836          * Gets the time of the event.
6837          * @return {Number}
6838          */
6839         getTime : function(){
6840             if(this.browserEvent){
6841                 return E.getTime(this.browserEvent);
6842             }
6843             return null;
6844         },
6845
6846         /**
6847          * Gets the page coordinates of the event.
6848          * @return {Array} The xy values like [x, y]
6849          */
6850         getXY : function(){
6851             return this.xy;
6852         },
6853
6854         /**
6855          * Gets the target for the event.
6856          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6857          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6858                 search as a number or element (defaults to 10 || document.body)
6859          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6860          * @return {HTMLelement}
6861          */
6862         getTarget : function(selector, maxDepth, returnEl){
6863             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6864         },
6865         /**
6866          * Gets the related target.
6867          * @return {HTMLElement}
6868          */
6869         getRelatedTarget : function(){
6870             if(this.browserEvent){
6871                 return E.getRelatedTarget(this.browserEvent);
6872             }
6873             return null;
6874         },
6875
6876         /**
6877          * Normalizes mouse wheel delta across browsers
6878          * @return {Number} The delta
6879          */
6880         getWheelDelta : function(){
6881             var e = this.browserEvent;
6882             var delta = 0;
6883             if(e.wheelDelta){ /* IE/Opera. */
6884                 delta = e.wheelDelta/120;
6885             }else if(e.detail){ /* Mozilla case. */
6886                 delta = -e.detail/3;
6887             }
6888             return delta;
6889         },
6890
6891         /**
6892          * Returns true if the control, meta, shift or alt key was pressed during this event.
6893          * @return {Boolean}
6894          */
6895         hasModifier : function(){
6896             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6897         },
6898
6899         /**
6900          * Returns true if the target of this event equals el or is a child of el
6901          * @param {String/HTMLElement/Element} el
6902          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6903          * @return {Boolean}
6904          */
6905         within : function(el, related){
6906             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6907             return t && Roo.fly(el).contains(t);
6908         },
6909
6910         getPoint : function(){
6911             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6912         }
6913     };
6914
6915     return new Roo.EventObjectImpl();
6916 }();
6917             
6918     /*
6919  * Based on:
6920  * Ext JS Library 1.1.1
6921  * Copyright(c) 2006-2007, Ext JS, LLC.
6922  *
6923  * Originally Released Under LGPL - original licence link has changed is not relivant.
6924  *
6925  * Fork - LGPL
6926  * <script type="text/javascript">
6927  */
6928
6929  
6930 // was in Composite Element!??!?!
6931  
6932 (function(){
6933     var D = Roo.lib.Dom;
6934     var E = Roo.lib.Event;
6935     var A = Roo.lib.Anim;
6936
6937     // local style camelizing for speed
6938     var propCache = {};
6939     var camelRe = /(-[a-z])/gi;
6940     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6941     var view = document.defaultView;
6942
6943 /**
6944  * @class Roo.Element
6945  * Represents an Element in the DOM.<br><br>
6946  * Usage:<br>
6947 <pre><code>
6948 var el = Roo.get("my-div");
6949
6950 // or with getEl
6951 var el = getEl("my-div");
6952
6953 // or with a DOM element
6954 var el = Roo.get(myDivElement);
6955 </code></pre>
6956  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6957  * each call instead of constructing a new one.<br><br>
6958  * <b>Animations</b><br />
6959  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6960  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6961 <pre>
6962 Option    Default   Description
6963 --------- --------  ---------------------------------------------
6964 duration  .35       The duration of the animation in seconds
6965 easing    easeOut   The YUI easing method
6966 callback  none      A function to execute when the anim completes
6967 scope     this      The scope (this) of the callback function
6968 </pre>
6969 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6970 * manipulate the animation. Here's an example:
6971 <pre><code>
6972 var el = Roo.get("my-div");
6973
6974 // no animation
6975 el.setWidth(100);
6976
6977 // default animation
6978 el.setWidth(100, true);
6979
6980 // animation with some options set
6981 el.setWidth(100, {
6982     duration: 1,
6983     callback: this.foo,
6984     scope: this
6985 });
6986
6987 // using the "anim" property to get the Anim object
6988 var opt = {
6989     duration: 1,
6990     callback: this.foo,
6991     scope: this
6992 };
6993 el.setWidth(100, opt);
6994 ...
6995 if(opt.anim.isAnimated()){
6996     opt.anim.stop();
6997 }
6998 </code></pre>
6999 * <b> Composite (Collections of) Elements</b><br />
7000  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7001  * @constructor Create a new Element directly.
7002  * @param {String/HTMLElement} element
7003  * @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).
7004  */
7005     Roo.Element = function(element, forceNew){
7006         var dom = typeof element == "string" ?
7007                 document.getElementById(element) : element;
7008         if(!dom){ // invalid id/element
7009             return null;
7010         }
7011         var id = dom.id;
7012         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7013             return Roo.Element.cache[id];
7014         }
7015
7016         /**
7017          * The DOM element
7018          * @type HTMLElement
7019          */
7020         this.dom = dom;
7021
7022         /**
7023          * The DOM element ID
7024          * @type String
7025          */
7026         this.id = id || Roo.id(dom);
7027     };
7028
7029     var El = Roo.Element;
7030
7031     El.prototype = {
7032         /**
7033          * The element's default display mode  (defaults to "")
7034          * @type String
7035          */
7036         originalDisplay : "",
7037
7038         visibilityMode : 1,
7039         /**
7040          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7041          * @type String
7042          */
7043         defaultUnit : "px",
7044         /**
7045          * Sets the element's visibility mode. When setVisible() is called it
7046          * will use this to determine whether to set the visibility or the display property.
7047          * @param visMode Element.VISIBILITY or Element.DISPLAY
7048          * @return {Roo.Element} this
7049          */
7050         setVisibilityMode : function(visMode){
7051             this.visibilityMode = visMode;
7052             return this;
7053         },
7054         /**
7055          * Convenience method for setVisibilityMode(Element.DISPLAY)
7056          * @param {String} display (optional) What to set display to when visible
7057          * @return {Roo.Element} this
7058          */
7059         enableDisplayMode : function(display){
7060             this.setVisibilityMode(El.DISPLAY);
7061             if(typeof display != "undefined") this.originalDisplay = display;
7062             return this;
7063         },
7064
7065         /**
7066          * 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)
7067          * @param {String} selector The simple selector to test
7068          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7069                 search as a number or element (defaults to 10 || document.body)
7070          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7071          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7072          */
7073         findParent : function(simpleSelector, maxDepth, returnEl){
7074             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7075             maxDepth = maxDepth || 50;
7076             if(typeof maxDepth != "number"){
7077                 stopEl = Roo.getDom(maxDepth);
7078                 maxDepth = 10;
7079             }
7080             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7081                 if(dq.is(p, simpleSelector)){
7082                     return returnEl ? Roo.get(p) : p;
7083                 }
7084                 depth++;
7085                 p = p.parentNode;
7086             }
7087             return null;
7088         },
7089
7090
7091         /**
7092          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7093          * @param {String} selector The simple selector to test
7094          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7095                 search as a number or element (defaults to 10 || document.body)
7096          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7097          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7098          */
7099         findParentNode : function(simpleSelector, maxDepth, returnEl){
7100             var p = Roo.fly(this.dom.parentNode, '_internal');
7101             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7102         },
7103
7104         /**
7105          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7106          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7107          * @param {String} selector The simple selector to test
7108          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7109                 search as a number or element (defaults to 10 || document.body)
7110          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7111          */
7112         up : function(simpleSelector, maxDepth){
7113             return this.findParentNode(simpleSelector, maxDepth, true);
7114         },
7115
7116
7117
7118         /**
7119          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7120          * @param {String} selector The simple selector to test
7121          * @return {Boolean} True if this element matches the selector, else false
7122          */
7123         is : function(simpleSelector){
7124             return Roo.DomQuery.is(this.dom, simpleSelector);
7125         },
7126
7127         /**
7128          * Perform animation on this element.
7129          * @param {Object} args The YUI animation control args
7130          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7131          * @param {Function} onComplete (optional) Function to call when animation completes
7132          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7133          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7134          * @return {Roo.Element} this
7135          */
7136         animate : function(args, duration, onComplete, easing, animType){
7137             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7138             return this;
7139         },
7140
7141         /*
7142          * @private Internal animation call
7143          */
7144         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7145             animType = animType || 'run';
7146             opt = opt || {};
7147             var anim = Roo.lib.Anim[animType](
7148                 this.dom, args,
7149                 (opt.duration || defaultDur) || .35,
7150                 (opt.easing || defaultEase) || 'easeOut',
7151                 function(){
7152                     Roo.callback(cb, this);
7153                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7154                 },
7155                 this
7156             );
7157             opt.anim = anim;
7158             return anim;
7159         },
7160
7161         // private legacy anim prep
7162         preanim : function(a, i){
7163             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7164         },
7165
7166         /**
7167          * Removes worthless text nodes
7168          * @param {Boolean} forceReclean (optional) By default the element
7169          * keeps track if it has been cleaned already so
7170          * you can call this over and over. However, if you update the element and
7171          * need to force a reclean, you can pass true.
7172          */
7173         clean : function(forceReclean){
7174             if(this.isCleaned && forceReclean !== true){
7175                 return this;
7176             }
7177             var ns = /\S/;
7178             var d = this.dom, n = d.firstChild, ni = -1;
7179             while(n){
7180                 var nx = n.nextSibling;
7181                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7182                     d.removeChild(n);
7183                 }else{
7184                     n.nodeIndex = ++ni;
7185                 }
7186                 n = nx;
7187             }
7188             this.isCleaned = true;
7189             return this;
7190         },
7191
7192         // private
7193         calcOffsetsTo : function(el){
7194             el = Roo.get(el);
7195             var d = el.dom;
7196             var restorePos = false;
7197             if(el.getStyle('position') == 'static'){
7198                 el.position('relative');
7199                 restorePos = true;
7200             }
7201             var x = 0, y =0;
7202             var op = this.dom;
7203             while(op && op != d && op.tagName != 'HTML'){
7204                 x+= op.offsetLeft;
7205                 y+= op.offsetTop;
7206                 op = op.offsetParent;
7207             }
7208             if(restorePos){
7209                 el.position('static');
7210             }
7211             return [x, y];
7212         },
7213
7214         /**
7215          * Scrolls this element into view within the passed container.
7216          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7217          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7218          * @return {Roo.Element} this
7219          */
7220         scrollIntoView : function(container, hscroll){
7221             var c = Roo.getDom(container) || document.body;
7222             var el = this.dom;
7223
7224             var o = this.calcOffsetsTo(c),
7225                 l = o[0],
7226                 t = o[1],
7227                 b = t+el.offsetHeight,
7228                 r = l+el.offsetWidth;
7229
7230             var ch = c.clientHeight;
7231             var ct = parseInt(c.scrollTop, 10);
7232             var cl = parseInt(c.scrollLeft, 10);
7233             var cb = ct + ch;
7234             var cr = cl + c.clientWidth;
7235
7236             if(t < ct){
7237                 c.scrollTop = t;
7238             }else if(b > cb){
7239                 c.scrollTop = b-ch;
7240             }
7241
7242             if(hscroll !== false){
7243                 if(l < cl){
7244                     c.scrollLeft = l;
7245                 }else if(r > cr){
7246                     c.scrollLeft = r-c.clientWidth;
7247                 }
7248             }
7249             return this;
7250         },
7251
7252         // private
7253         scrollChildIntoView : function(child, hscroll){
7254             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7255         },
7256
7257         /**
7258          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7259          * the new height may not be available immediately.
7260          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7261          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7262          * @param {Function} onComplete (optional) Function to call when animation completes
7263          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7264          * @return {Roo.Element} this
7265          */
7266         autoHeight : function(animate, duration, onComplete, easing){
7267             var oldHeight = this.getHeight();
7268             this.clip();
7269             this.setHeight(1); // force clipping
7270             setTimeout(function(){
7271                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7272                 if(!animate){
7273                     this.setHeight(height);
7274                     this.unclip();
7275                     if(typeof onComplete == "function"){
7276                         onComplete();
7277                     }
7278                 }else{
7279                     this.setHeight(oldHeight); // restore original height
7280                     this.setHeight(height, animate, duration, function(){
7281                         this.unclip();
7282                         if(typeof onComplete == "function") onComplete();
7283                     }.createDelegate(this), easing);
7284                 }
7285             }.createDelegate(this), 0);
7286             return this;
7287         },
7288
7289         /**
7290          * Returns true if this element is an ancestor of the passed element
7291          * @param {HTMLElement/String} el The element to check
7292          * @return {Boolean} True if this element is an ancestor of el, else false
7293          */
7294         contains : function(el){
7295             if(!el){return false;}
7296             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7297         },
7298
7299         /**
7300          * Checks whether the element is currently visible using both visibility and display properties.
7301          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7302          * @return {Boolean} True if the element is currently visible, else false
7303          */
7304         isVisible : function(deep) {
7305             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7306             if(deep !== true || !vis){
7307                 return vis;
7308             }
7309             var p = this.dom.parentNode;
7310             while(p && p.tagName.toLowerCase() != "body"){
7311                 if(!Roo.fly(p, '_isVisible').isVisible()){
7312                     return false;
7313                 }
7314                 p = p.parentNode;
7315             }
7316             return true;
7317         },
7318
7319         /**
7320          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7321          * @param {String} selector The CSS selector
7322          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7323          * @return {CompositeElement/CompositeElementLite} The composite element
7324          */
7325         select : function(selector, unique){
7326             return El.select(selector, unique, this.dom);
7327         },
7328
7329         /**
7330          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7331          * @param {String} selector The CSS selector
7332          * @return {Array} An array of the matched nodes
7333          */
7334         query : function(selector, unique){
7335             return Roo.DomQuery.select(selector, this.dom);
7336         },
7337
7338         /**
7339          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7340          * @param {String} selector The CSS selector
7341          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7342          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7343          */
7344         child : function(selector, returnDom){
7345             var n = Roo.DomQuery.selectNode(selector, this.dom);
7346             return returnDom ? n : Roo.get(n);
7347         },
7348
7349         /**
7350          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7351          * @param {String} selector The CSS selector
7352          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7353          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7354          */
7355         down : function(selector, returnDom){
7356             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7357             return returnDom ? n : Roo.get(n);
7358         },
7359
7360         /**
7361          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7362          * @param {String} group The group the DD object is member of
7363          * @param {Object} config The DD config object
7364          * @param {Object} overrides An object containing methods to override/implement on the DD object
7365          * @return {Roo.dd.DD} The DD object
7366          */
7367         initDD : function(group, config, overrides){
7368             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7369             return Roo.apply(dd, overrides);
7370         },
7371
7372         /**
7373          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7374          * @param {String} group The group the DDProxy object is member of
7375          * @param {Object} config The DDProxy config object
7376          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7377          * @return {Roo.dd.DDProxy} The DDProxy object
7378          */
7379         initDDProxy : function(group, config, overrides){
7380             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7381             return Roo.apply(dd, overrides);
7382         },
7383
7384         /**
7385          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7386          * @param {String} group The group the DDTarget object is member of
7387          * @param {Object} config The DDTarget config object
7388          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7389          * @return {Roo.dd.DDTarget} The DDTarget object
7390          */
7391         initDDTarget : function(group, config, overrides){
7392             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7393             return Roo.apply(dd, overrides);
7394         },
7395
7396         /**
7397          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7398          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7399          * @param {Boolean} visible Whether the element is visible
7400          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7401          * @return {Roo.Element} this
7402          */
7403          setVisible : function(visible, animate){
7404             if(!animate || !A){
7405                 if(this.visibilityMode == El.DISPLAY){
7406                     this.setDisplayed(visible);
7407                 }else{
7408                     this.fixDisplay();
7409                     this.dom.style.visibility = visible ? "visible" : "hidden";
7410                 }
7411             }else{
7412                 // closure for composites
7413                 var dom = this.dom;
7414                 var visMode = this.visibilityMode;
7415                 if(visible){
7416                     this.setOpacity(.01);
7417                     this.setVisible(true);
7418                 }
7419                 this.anim({opacity: { to: (visible?1:0) }},
7420                       this.preanim(arguments, 1),
7421                       null, .35, 'easeIn', function(){
7422                          if(!visible){
7423                              if(visMode == El.DISPLAY){
7424                                  dom.style.display = "none";
7425                              }else{
7426                                  dom.style.visibility = "hidden";
7427                              }
7428                              Roo.get(dom).setOpacity(1);
7429                          }
7430                      });
7431             }
7432             return this;
7433         },
7434
7435         /**
7436          * Returns true if display is not "none"
7437          * @return {Boolean}
7438          */
7439         isDisplayed : function() {
7440             return this.getStyle("display") != "none";
7441         },
7442
7443         /**
7444          * Toggles the element's visibility or display, depending on visibility mode.
7445          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7446          * @return {Roo.Element} this
7447          */
7448         toggle : function(animate){
7449             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7450             return this;
7451         },
7452
7453         /**
7454          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7455          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7456          * @return {Roo.Element} this
7457          */
7458         setDisplayed : function(value) {
7459             if(typeof value == "boolean"){
7460                value = value ? this.originalDisplay : "none";
7461             }
7462             this.setStyle("display", value);
7463             return this;
7464         },
7465
7466         /**
7467          * Tries to focus the element. Any exceptions are caught and ignored.
7468          * @return {Roo.Element} this
7469          */
7470         focus : function() {
7471             try{
7472                 this.dom.focus();
7473             }catch(e){}
7474             return this;
7475         },
7476
7477         /**
7478          * Tries to blur the element. Any exceptions are caught and ignored.
7479          * @return {Roo.Element} this
7480          */
7481         blur : function() {
7482             try{
7483                 this.dom.blur();
7484             }catch(e){}
7485             return this;
7486         },
7487
7488         /**
7489          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7490          * @param {String/Array} className The CSS class to add, or an array of classes
7491          * @return {Roo.Element} this
7492          */
7493         addClass : function(className){
7494             if(className instanceof Array){
7495                 for(var i = 0, len = className.length; i < len; i++) {
7496                     this.addClass(className[i]);
7497                 }
7498             }else{
7499                 if(className && !this.hasClass(className)){
7500                     this.dom.className = this.dom.className + " " + className;
7501                 }
7502             }
7503             return this;
7504         },
7505
7506         /**
7507          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7508          * @param {String/Array} className The CSS class to add, or an array of classes
7509          * @return {Roo.Element} this
7510          */
7511         radioClass : function(className){
7512             var siblings = this.dom.parentNode.childNodes;
7513             for(var i = 0; i < siblings.length; i++) {
7514                 var s = siblings[i];
7515                 if(s.nodeType == 1){
7516                     Roo.get(s).removeClass(className);
7517                 }
7518             }
7519             this.addClass(className);
7520             return this;
7521         },
7522
7523         /**
7524          * Removes one or more CSS classes from the element.
7525          * @param {String/Array} className The CSS class to remove, or an array of classes
7526          * @return {Roo.Element} this
7527          */
7528         removeClass : function(className){
7529             if(!className || !this.dom.className){
7530                 return this;
7531             }
7532             if(className instanceof Array){
7533                 for(var i = 0, len = className.length; i < len; i++) {
7534                     this.removeClass(className[i]);
7535                 }
7536             }else{
7537                 if(this.hasClass(className)){
7538                     var re = this.classReCache[className];
7539                     if (!re) {
7540                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7541                        this.classReCache[className] = re;
7542                     }
7543                     this.dom.className =
7544                         this.dom.className.replace(re, " ");
7545                 }
7546             }
7547             return this;
7548         },
7549
7550         // private
7551         classReCache: {},
7552
7553         /**
7554          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7555          * @param {String} className The CSS class to toggle
7556          * @return {Roo.Element} this
7557          */
7558         toggleClass : function(className){
7559             if(this.hasClass(className)){
7560                 this.removeClass(className);
7561             }else{
7562                 this.addClass(className);
7563             }
7564             return this;
7565         },
7566
7567         /**
7568          * Checks if the specified CSS class exists on this element's DOM node.
7569          * @param {String} className The CSS class to check for
7570          * @return {Boolean} True if the class exists, else false
7571          */
7572         hasClass : function(className){
7573             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7574         },
7575
7576         /**
7577          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7578          * @param {String} oldClassName The CSS class to replace
7579          * @param {String} newClassName The replacement CSS class
7580          * @return {Roo.Element} this
7581          */
7582         replaceClass : function(oldClassName, newClassName){
7583             this.removeClass(oldClassName);
7584             this.addClass(newClassName);
7585             return this;
7586         },
7587
7588         /**
7589          * Returns an object with properties matching the styles requested.
7590          * For example, el.getStyles('color', 'font-size', 'width') might return
7591          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7592          * @param {String} style1 A style name
7593          * @param {String} style2 A style name
7594          * @param {String} etc.
7595          * @return {Object} The style object
7596          */
7597         getStyles : function(){
7598             var a = arguments, len = a.length, r = {};
7599             for(var i = 0; i < len; i++){
7600                 r[a[i]] = this.getStyle(a[i]);
7601             }
7602             return r;
7603         },
7604
7605         /**
7606          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7607          * @param {String} property The style property whose value is returned.
7608          * @return {String} The current value of the style property for this element.
7609          */
7610         getStyle : function(){
7611             return view && view.getComputedStyle ?
7612                 function(prop){
7613                     var el = this.dom, v, cs, camel;
7614                     if(prop == 'float'){
7615                         prop = "cssFloat";
7616                     }
7617                     if(el.style && (v = el.style[prop])){
7618                         return v;
7619                     }
7620                     if(cs = view.getComputedStyle(el, "")){
7621                         if(!(camel = propCache[prop])){
7622                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7623                         }
7624                         return cs[camel];
7625                     }
7626                     return null;
7627                 } :
7628                 function(prop){
7629                     var el = this.dom, v, cs, camel;
7630                     if(prop == 'opacity'){
7631                         if(typeof el.style.filter == 'string'){
7632                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7633                             if(m){
7634                                 var fv = parseFloat(m[1]);
7635                                 if(!isNaN(fv)){
7636                                     return fv ? fv / 100 : 0;
7637                                 }
7638                             }
7639                         }
7640                         return 1;
7641                     }else if(prop == 'float'){
7642                         prop = "styleFloat";
7643                     }
7644                     if(!(camel = propCache[prop])){
7645                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7646                     }
7647                     if(v = el.style[camel]){
7648                         return v;
7649                     }
7650                     if(cs = el.currentStyle){
7651                         return cs[camel];
7652                     }
7653                     return null;
7654                 };
7655         }(),
7656
7657         /**
7658          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7659          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7660          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7661          * @return {Roo.Element} this
7662          */
7663         setStyle : function(prop, value){
7664             if(typeof prop == "string"){
7665                 
7666                 if (prop == 'float') {
7667                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7668                     return this;
7669                 }
7670                 
7671                 var camel;
7672                 if(!(camel = propCache[prop])){
7673                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7674                 }
7675                 
7676                 if(camel == 'opacity') {
7677                     this.setOpacity(value);
7678                 }else{
7679                     this.dom.style[camel] = value;
7680                 }
7681             }else{
7682                 for(var style in prop){
7683                     if(typeof prop[style] != "function"){
7684                        this.setStyle(style, prop[style]);
7685                     }
7686                 }
7687             }
7688             return this;
7689         },
7690
7691         /**
7692          * More flexible version of {@link #setStyle} for setting style properties.
7693          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7694          * a function which returns such a specification.
7695          * @return {Roo.Element} this
7696          */
7697         applyStyles : function(style){
7698             Roo.DomHelper.applyStyles(this.dom, style);
7699             return this;
7700         },
7701
7702         /**
7703           * 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).
7704           * @return {Number} The X position of the element
7705           */
7706         getX : function(){
7707             return D.getX(this.dom);
7708         },
7709
7710         /**
7711           * 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).
7712           * @return {Number} The Y position of the element
7713           */
7714         getY : function(){
7715             return D.getY(this.dom);
7716         },
7717
7718         /**
7719           * 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).
7720           * @return {Array} The XY position of the element
7721           */
7722         getXY : function(){
7723             return D.getXY(this.dom);
7724         },
7725
7726         /**
7727          * 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).
7728          * @param {Number} The X position of the element
7729          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7730          * @return {Roo.Element} this
7731          */
7732         setX : function(x, animate){
7733             if(!animate || !A){
7734                 D.setX(this.dom, x);
7735             }else{
7736                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7737             }
7738             return this;
7739         },
7740
7741         /**
7742          * 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).
7743          * @param {Number} The Y position of the element
7744          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7745          * @return {Roo.Element} this
7746          */
7747         setY : function(y, animate){
7748             if(!animate || !A){
7749                 D.setY(this.dom, y);
7750             }else{
7751                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7752             }
7753             return this;
7754         },
7755
7756         /**
7757          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7758          * @param {String} left The left CSS property value
7759          * @return {Roo.Element} this
7760          */
7761         setLeft : function(left){
7762             this.setStyle("left", this.addUnits(left));
7763             return this;
7764         },
7765
7766         /**
7767          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7768          * @param {String} top The top CSS property value
7769          * @return {Roo.Element} this
7770          */
7771         setTop : function(top){
7772             this.setStyle("top", this.addUnits(top));
7773             return this;
7774         },
7775
7776         /**
7777          * Sets the element's CSS right style.
7778          * @param {String} right The right CSS property value
7779          * @return {Roo.Element} this
7780          */
7781         setRight : function(right){
7782             this.setStyle("right", this.addUnits(right));
7783             return this;
7784         },
7785
7786         /**
7787          * Sets the element's CSS bottom style.
7788          * @param {String} bottom The bottom CSS property value
7789          * @return {Roo.Element} this
7790          */
7791         setBottom : function(bottom){
7792             this.setStyle("bottom", this.addUnits(bottom));
7793             return this;
7794         },
7795
7796         /**
7797          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7798          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7799          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7800          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7801          * @return {Roo.Element} this
7802          */
7803         setXY : function(pos, animate){
7804             if(!animate || !A){
7805                 D.setXY(this.dom, pos);
7806             }else{
7807                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7808             }
7809             return this;
7810         },
7811
7812         /**
7813          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7814          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7815          * @param {Number} x X value for new position (coordinates are page-based)
7816          * @param {Number} y Y value for new position (coordinates are page-based)
7817          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7818          * @return {Roo.Element} this
7819          */
7820         setLocation : function(x, y, animate){
7821             this.setXY([x, y], this.preanim(arguments, 2));
7822             return this;
7823         },
7824
7825         /**
7826          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7827          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7828          * @param {Number} x X value for new position (coordinates are page-based)
7829          * @param {Number} y Y value for new position (coordinates are page-based)
7830          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7831          * @return {Roo.Element} this
7832          */
7833         moveTo : function(x, y, animate){
7834             this.setXY([x, y], this.preanim(arguments, 2));
7835             return this;
7836         },
7837
7838         /**
7839          * Returns the region of the given element.
7840          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7841          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7842          */
7843         getRegion : function(){
7844             return D.getRegion(this.dom);
7845         },
7846
7847         /**
7848          * Returns the offset height of the element
7849          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7850          * @return {Number} The element's height
7851          */
7852         getHeight : function(contentHeight){
7853             var h = this.dom.offsetHeight || 0;
7854             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7855         },
7856
7857         /**
7858          * Returns the offset width of the element
7859          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7860          * @return {Number} The element's width
7861          */
7862         getWidth : function(contentWidth){
7863             var w = this.dom.offsetWidth || 0;
7864             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7865         },
7866
7867         /**
7868          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7869          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7870          * if a height has not been set using CSS.
7871          * @return {Number}
7872          */
7873         getComputedHeight : function(){
7874             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7875             if(!h){
7876                 h = parseInt(this.getStyle('height'), 10) || 0;
7877                 if(!this.isBorderBox()){
7878                     h += this.getFrameWidth('tb');
7879                 }
7880             }
7881             return h;
7882         },
7883
7884         /**
7885          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7886          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7887          * if a width has not been set using CSS.
7888          * @return {Number}
7889          */
7890         getComputedWidth : function(){
7891             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7892             if(!w){
7893                 w = parseInt(this.getStyle('width'), 10) || 0;
7894                 if(!this.isBorderBox()){
7895                     w += this.getFrameWidth('lr');
7896                 }
7897             }
7898             return w;
7899         },
7900
7901         /**
7902          * Returns the size of the element.
7903          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7904          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7905          */
7906         getSize : function(contentSize){
7907             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7908         },
7909
7910         /**
7911          * Returns the width and height of the viewport.
7912          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7913          */
7914         getViewSize : function(){
7915             var d = this.dom, doc = document, aw = 0, ah = 0;
7916             if(d == doc || d == doc.body){
7917                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7918             }else{
7919                 return {
7920                     width : d.clientWidth,
7921                     height: d.clientHeight
7922                 };
7923             }
7924         },
7925
7926         /**
7927          * Returns the value of the "value" attribute
7928          * @param {Boolean} asNumber true to parse the value as a number
7929          * @return {String/Number}
7930          */
7931         getValue : function(asNumber){
7932             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7933         },
7934
7935         // private
7936         adjustWidth : function(width){
7937             if(typeof width == "number"){
7938                 if(this.autoBoxAdjust && !this.isBorderBox()){
7939                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7940                 }
7941                 if(width < 0){
7942                     width = 0;
7943                 }
7944             }
7945             return width;
7946         },
7947
7948         // private
7949         adjustHeight : function(height){
7950             if(typeof height == "number"){
7951                if(this.autoBoxAdjust && !this.isBorderBox()){
7952                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7953                }
7954                if(height < 0){
7955                    height = 0;
7956                }
7957             }
7958             return height;
7959         },
7960
7961         /**
7962          * Set the width of the element
7963          * @param {Number} width The new width
7964          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7965          * @return {Roo.Element} this
7966          */
7967         setWidth : function(width, animate){
7968             width = this.adjustWidth(width);
7969             if(!animate || !A){
7970                 this.dom.style.width = this.addUnits(width);
7971             }else{
7972                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7973             }
7974             return this;
7975         },
7976
7977         /**
7978          * Set the height of the element
7979          * @param {Number} height The new height
7980          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7981          * @return {Roo.Element} this
7982          */
7983          setHeight : function(height, animate){
7984             height = this.adjustHeight(height);
7985             if(!animate || !A){
7986                 this.dom.style.height = this.addUnits(height);
7987             }else{
7988                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7989             }
7990             return this;
7991         },
7992
7993         /**
7994          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7995          * @param {Number} width The new width
7996          * @param {Number} height The new height
7997          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7998          * @return {Roo.Element} this
7999          */
8000          setSize : function(width, height, animate){
8001             if(typeof width == "object"){ // in case of object from getSize()
8002                 height = width.height; width = width.width;
8003             }
8004             width = this.adjustWidth(width); height = this.adjustHeight(height);
8005             if(!animate || !A){
8006                 this.dom.style.width = this.addUnits(width);
8007                 this.dom.style.height = this.addUnits(height);
8008             }else{
8009                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8010             }
8011             return this;
8012         },
8013
8014         /**
8015          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8016          * @param {Number} x X value for new position (coordinates are page-based)
8017          * @param {Number} y Y value for new position (coordinates are page-based)
8018          * @param {Number} width The new width
8019          * @param {Number} height The new height
8020          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8021          * @return {Roo.Element} this
8022          */
8023         setBounds : function(x, y, width, height, animate){
8024             if(!animate || !A){
8025                 this.setSize(width, height);
8026                 this.setLocation(x, y);
8027             }else{
8028                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8029                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8030                               this.preanim(arguments, 4), 'motion');
8031             }
8032             return this;
8033         },
8034
8035         /**
8036          * 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.
8037          * @param {Roo.lib.Region} region The region to fill
8038          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8039          * @return {Roo.Element} this
8040          */
8041         setRegion : function(region, animate){
8042             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8043             return this;
8044         },
8045
8046         /**
8047          * Appends an event handler
8048          *
8049          * @param {String}   eventName     The type of event to append
8050          * @param {Function} fn        The method the event invokes
8051          * @param {Object} scope       (optional) The scope (this object) of the fn
8052          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8053          */
8054         addListener : function(eventName, fn, scope, options){
8055             if (this.dom) {
8056                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8057             }
8058         },
8059
8060         /**
8061          * Removes an event handler from this element
8062          * @param {String} eventName the type of event to remove
8063          * @param {Function} fn the method the event invokes
8064          * @return {Roo.Element} this
8065          */
8066         removeListener : function(eventName, fn){
8067             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8068             return this;
8069         },
8070
8071         /**
8072          * Removes all previous added listeners from this element
8073          * @return {Roo.Element} this
8074          */
8075         removeAllListeners : function(){
8076             E.purgeElement(this.dom);
8077             return this;
8078         },
8079
8080         relayEvent : function(eventName, observable){
8081             this.on(eventName, function(e){
8082                 observable.fireEvent(eventName, e);
8083             });
8084         },
8085
8086         /**
8087          * Set the opacity of the element
8088          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8089          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8090          * @return {Roo.Element} this
8091          */
8092          setOpacity : function(opacity, animate){
8093             if(!animate || !A){
8094                 var s = this.dom.style;
8095                 if(Roo.isIE){
8096                     s.zoom = 1;
8097                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8098                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8099                 }else{
8100                     s.opacity = opacity;
8101                 }
8102             }else{
8103                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8104             }
8105             return this;
8106         },
8107
8108         /**
8109          * Gets the left X coordinate
8110          * @param {Boolean} local True to get the local css position instead of page coordinate
8111          * @return {Number}
8112          */
8113         getLeft : function(local){
8114             if(!local){
8115                 return this.getX();
8116             }else{
8117                 return parseInt(this.getStyle("left"), 10) || 0;
8118             }
8119         },
8120
8121         /**
8122          * Gets the right X coordinate of the element (element X position + element width)
8123          * @param {Boolean} local True to get the local css position instead of page coordinate
8124          * @return {Number}
8125          */
8126         getRight : function(local){
8127             if(!local){
8128                 return this.getX() + this.getWidth();
8129             }else{
8130                 return (this.getLeft(true) + this.getWidth()) || 0;
8131             }
8132         },
8133
8134         /**
8135          * Gets the top Y coordinate
8136          * @param {Boolean} local True to get the local css position instead of page coordinate
8137          * @return {Number}
8138          */
8139         getTop : function(local) {
8140             if(!local){
8141                 return this.getY();
8142             }else{
8143                 return parseInt(this.getStyle("top"), 10) || 0;
8144             }
8145         },
8146
8147         /**
8148          * Gets the bottom Y coordinate of the element (element Y position + element height)
8149          * @param {Boolean} local True to get the local css position instead of page coordinate
8150          * @return {Number}
8151          */
8152         getBottom : function(local){
8153             if(!local){
8154                 return this.getY() + this.getHeight();
8155             }else{
8156                 return (this.getTop(true) + this.getHeight()) || 0;
8157             }
8158         },
8159
8160         /**
8161         * Initializes positioning on this element. If a desired position is not passed, it will make the
8162         * the element positioned relative IF it is not already positioned.
8163         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8164         * @param {Number} zIndex (optional) The zIndex to apply
8165         * @param {Number} x (optional) Set the page X position
8166         * @param {Number} y (optional) Set the page Y position
8167         */
8168         position : function(pos, zIndex, x, y){
8169             if(!pos){
8170                if(this.getStyle('position') == 'static'){
8171                    this.setStyle('position', 'relative');
8172                }
8173             }else{
8174                 this.setStyle("position", pos);
8175             }
8176             if(zIndex){
8177                 this.setStyle("z-index", zIndex);
8178             }
8179             if(x !== undefined && y !== undefined){
8180                 this.setXY([x, y]);
8181             }else if(x !== undefined){
8182                 this.setX(x);
8183             }else if(y !== undefined){
8184                 this.setY(y);
8185             }
8186         },
8187
8188         /**
8189         * Clear positioning back to the default when the document was loaded
8190         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8191         * @return {Roo.Element} this
8192          */
8193         clearPositioning : function(value){
8194             value = value ||'';
8195             this.setStyle({
8196                 "left": value,
8197                 "right": value,
8198                 "top": value,
8199                 "bottom": value,
8200                 "z-index": "",
8201                 "position" : "static"
8202             });
8203             return this;
8204         },
8205
8206         /**
8207         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8208         * snapshot before performing an update and then restoring the element.
8209         * @return {Object}
8210         */
8211         getPositioning : function(){
8212             var l = this.getStyle("left");
8213             var t = this.getStyle("top");
8214             return {
8215                 "position" : this.getStyle("position"),
8216                 "left" : l,
8217                 "right" : l ? "" : this.getStyle("right"),
8218                 "top" : t,
8219                 "bottom" : t ? "" : this.getStyle("bottom"),
8220                 "z-index" : this.getStyle("z-index")
8221             };
8222         },
8223
8224         /**
8225          * Gets the width of the border(s) for the specified side(s)
8226          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8227          * passing lr would get the border (l)eft width + the border (r)ight width.
8228          * @return {Number} The width of the sides passed added together
8229          */
8230         getBorderWidth : function(side){
8231             return this.addStyles(side, El.borders);
8232         },
8233
8234         /**
8235          * Gets the width of the padding(s) for the specified side(s)
8236          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8237          * passing lr would get the padding (l)eft + the padding (r)ight.
8238          * @return {Number} The padding of the sides passed added together
8239          */
8240         getPadding : function(side){
8241             return this.addStyles(side, El.paddings);
8242         },
8243
8244         /**
8245         * Set positioning with an object returned by getPositioning().
8246         * @param {Object} posCfg
8247         * @return {Roo.Element} this
8248          */
8249         setPositioning : function(pc){
8250             this.applyStyles(pc);
8251             if(pc.right == "auto"){
8252                 this.dom.style.right = "";
8253             }
8254             if(pc.bottom == "auto"){
8255                 this.dom.style.bottom = "";
8256             }
8257             return this;
8258         },
8259
8260         // private
8261         fixDisplay : function(){
8262             if(this.getStyle("display") == "none"){
8263                 this.setStyle("visibility", "hidden");
8264                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8265                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8266                     this.setStyle("display", "block");
8267                 }
8268             }
8269         },
8270
8271         /**
8272          * Quick set left and top adding default units
8273          * @param {String} left The left CSS property value
8274          * @param {String} top The top CSS property value
8275          * @return {Roo.Element} this
8276          */
8277          setLeftTop : function(left, top){
8278             this.dom.style.left = this.addUnits(left);
8279             this.dom.style.top = this.addUnits(top);
8280             return this;
8281         },
8282
8283         /**
8284          * Move this element relative to its current position.
8285          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8286          * @param {Number} distance How far to move the element in pixels
8287          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8288          * @return {Roo.Element} this
8289          */
8290          move : function(direction, distance, animate){
8291             var xy = this.getXY();
8292             direction = direction.toLowerCase();
8293             switch(direction){
8294                 case "l":
8295                 case "left":
8296                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8297                     break;
8298                case "r":
8299                case "right":
8300                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8301                     break;
8302                case "t":
8303                case "top":
8304                case "up":
8305                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8306                     break;
8307                case "b":
8308                case "bottom":
8309                case "down":
8310                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8311                     break;
8312             }
8313             return this;
8314         },
8315
8316         /**
8317          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8318          * @return {Roo.Element} this
8319          */
8320         clip : function(){
8321             if(!this.isClipped){
8322                this.isClipped = true;
8323                this.originalClip = {
8324                    "o": this.getStyle("overflow"),
8325                    "x": this.getStyle("overflow-x"),
8326                    "y": this.getStyle("overflow-y")
8327                };
8328                this.setStyle("overflow", "hidden");
8329                this.setStyle("overflow-x", "hidden");
8330                this.setStyle("overflow-y", "hidden");
8331             }
8332             return this;
8333         },
8334
8335         /**
8336          *  Return clipping (overflow) to original clipping before clip() was called
8337          * @return {Roo.Element} this
8338          */
8339         unclip : function(){
8340             if(this.isClipped){
8341                 this.isClipped = false;
8342                 var o = this.originalClip;
8343                 if(o.o){this.setStyle("overflow", o.o);}
8344                 if(o.x){this.setStyle("overflow-x", o.x);}
8345                 if(o.y){this.setStyle("overflow-y", o.y);}
8346             }
8347             return this;
8348         },
8349
8350
8351         /**
8352          * Gets the x,y coordinates specified by the anchor position on the element.
8353          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8354          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8355          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8356          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8357          * @return {Array} [x, y] An array containing the element's x and y coordinates
8358          */
8359         getAnchorXY : function(anchor, local, s){
8360             //Passing a different size is useful for pre-calculating anchors,
8361             //especially for anchored animations that change the el size.
8362
8363             var w, h, vp = false;
8364             if(!s){
8365                 var d = this.dom;
8366                 if(d == document.body || d == document){
8367                     vp = true;
8368                     w = D.getViewWidth(); h = D.getViewHeight();
8369                 }else{
8370                     w = this.getWidth(); h = this.getHeight();
8371                 }
8372             }else{
8373                 w = s.width;  h = s.height;
8374             }
8375             var x = 0, y = 0, r = Math.round;
8376             switch((anchor || "tl").toLowerCase()){
8377                 case "c":
8378                     x = r(w*.5);
8379                     y = r(h*.5);
8380                 break;
8381                 case "t":
8382                     x = r(w*.5);
8383                     y = 0;
8384                 break;
8385                 case "l":
8386                     x = 0;
8387                     y = r(h*.5);
8388                 break;
8389                 case "r":
8390                     x = w;
8391                     y = r(h*.5);
8392                 break;
8393                 case "b":
8394                     x = r(w*.5);
8395                     y = h;
8396                 break;
8397                 case "tl":
8398                     x = 0;
8399                     y = 0;
8400                 break;
8401                 case "bl":
8402                     x = 0;
8403                     y = h;
8404                 break;
8405                 case "br":
8406                     x = w;
8407                     y = h;
8408                 break;
8409                 case "tr":
8410                     x = w;
8411                     y = 0;
8412                 break;
8413             }
8414             if(local === true){
8415                 return [x, y];
8416             }
8417             if(vp){
8418                 var sc = this.getScroll();
8419                 return [x + sc.left, y + sc.top];
8420             }
8421             //Add the element's offset xy
8422             var o = this.getXY();
8423             return [x+o[0], y+o[1]];
8424         },
8425
8426         /**
8427          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8428          * supported position values.
8429          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8430          * @param {String} position The position to align to.
8431          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8432          * @return {Array} [x, y]
8433          */
8434         getAlignToXY : function(el, p, o){
8435             el = Roo.get(el);
8436             var d = this.dom;
8437             if(!el.dom){
8438                 throw "Element.alignTo with an element that doesn't exist";
8439             }
8440             var c = false; //constrain to viewport
8441             var p1 = "", p2 = "";
8442             o = o || [0,0];
8443
8444             if(!p){
8445                 p = "tl-bl";
8446             }else if(p == "?"){
8447                 p = "tl-bl?";
8448             }else if(p.indexOf("-") == -1){
8449                 p = "tl-" + p;
8450             }
8451             p = p.toLowerCase();
8452             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8453             if(!m){
8454                throw "Element.alignTo with an invalid alignment " + p;
8455             }
8456             p1 = m[1]; p2 = m[2]; c = !!m[3];
8457
8458             //Subtract the aligned el's internal xy from the target's offset xy
8459             //plus custom offset to get the aligned el's new offset xy
8460             var a1 = this.getAnchorXY(p1, true);
8461             var a2 = el.getAnchorXY(p2, false);
8462             var x = a2[0] - a1[0] + o[0];
8463             var y = a2[1] - a1[1] + o[1];
8464             if(c){
8465                 //constrain the aligned el to viewport if necessary
8466                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8467                 // 5px of margin for ie
8468                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8469
8470                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8471                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8472                 //otherwise swap the aligned el to the opposite border of the target.
8473                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8474                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8475                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8476                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8477
8478                var doc = document;
8479                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8480                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8481
8482                if((x+w) > dw + scrollX){
8483                     x = swapX ? r.left-w : dw+scrollX-w;
8484                 }
8485                if(x < scrollX){
8486                    x = swapX ? r.right : scrollX;
8487                }
8488                if((y+h) > dh + scrollY){
8489                     y = swapY ? r.top-h : dh+scrollY-h;
8490                 }
8491                if (y < scrollY){
8492                    y = swapY ? r.bottom : scrollY;
8493                }
8494             }
8495             return [x,y];
8496         },
8497
8498         // private
8499         getConstrainToXY : function(){
8500             var os = {top:0, left:0, bottom:0, right: 0};
8501
8502             return function(el, local, offsets, proposedXY){
8503                 el = Roo.get(el);
8504                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8505
8506                 var vw, vh, vx = 0, vy = 0;
8507                 if(el.dom == document.body || el.dom == document){
8508                     vw = Roo.lib.Dom.getViewWidth();
8509                     vh = Roo.lib.Dom.getViewHeight();
8510                 }else{
8511                     vw = el.dom.clientWidth;
8512                     vh = el.dom.clientHeight;
8513                     if(!local){
8514                         var vxy = el.getXY();
8515                         vx = vxy[0];
8516                         vy = vxy[1];
8517                     }
8518                 }
8519
8520                 var s = el.getScroll();
8521
8522                 vx += offsets.left + s.left;
8523                 vy += offsets.top + s.top;
8524
8525                 vw -= offsets.right;
8526                 vh -= offsets.bottom;
8527
8528                 var vr = vx+vw;
8529                 var vb = vy+vh;
8530
8531                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8532                 var x = xy[0], y = xy[1];
8533                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8534
8535                 // only move it if it needs it
8536                 var moved = false;
8537
8538                 // first validate right/bottom
8539                 if((x + w) > vr){
8540                     x = vr - w;
8541                     moved = true;
8542                 }
8543                 if((y + h) > vb){
8544                     y = vb - h;
8545                     moved = true;
8546                 }
8547                 // then make sure top/left isn't negative
8548                 if(x < vx){
8549                     x = vx;
8550                     moved = true;
8551                 }
8552                 if(y < vy){
8553                     y = vy;
8554                     moved = true;
8555                 }
8556                 return moved ? [x, y] : false;
8557             };
8558         }(),
8559
8560         // private
8561         adjustForConstraints : function(xy, parent, offsets){
8562             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8563         },
8564
8565         /**
8566          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8567          * document it aligns it to the viewport.
8568          * The position parameter is optional, and can be specified in any one of the following formats:
8569          * <ul>
8570          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8571          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8572          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8573          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8574          *   <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
8575          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8576          * </ul>
8577          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8578          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8579          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8580          * that specified in order to enforce the viewport constraints.
8581          * Following are all of the supported anchor positions:
8582     <pre>
8583     Value  Description
8584     -----  -----------------------------
8585     tl     The top left corner (default)
8586     t      The center of the top edge
8587     tr     The top right corner
8588     l      The center of the left edge
8589     c      In the center of the element
8590     r      The center of the right edge
8591     bl     The bottom left corner
8592     b      The center of the bottom edge
8593     br     The bottom right corner
8594     </pre>
8595     Example Usage:
8596     <pre><code>
8597     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8598     el.alignTo("other-el");
8599
8600     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8601     el.alignTo("other-el", "tr?");
8602
8603     // align the bottom right corner of el with the center left edge of other-el
8604     el.alignTo("other-el", "br-l?");
8605
8606     // align the center of el with the bottom left corner of other-el and
8607     // adjust the x position by -6 pixels (and the y position by 0)
8608     el.alignTo("other-el", "c-bl", [-6, 0]);
8609     </code></pre>
8610          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8611          * @param {String} position The position to align to.
8612          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8613          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8614          * @return {Roo.Element} this
8615          */
8616         alignTo : function(element, position, offsets, animate){
8617             var xy = this.getAlignToXY(element, position, offsets);
8618             this.setXY(xy, this.preanim(arguments, 3));
8619             return this;
8620         },
8621
8622         /**
8623          * Anchors an element to another element and realigns it when the window is resized.
8624          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8625          * @param {String} position The position to align to.
8626          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8627          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8628          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8629          * is a number, it is used as the buffer delay (defaults to 50ms).
8630          * @param {Function} callback The function to call after the animation finishes
8631          * @return {Roo.Element} this
8632          */
8633         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8634             var action = function(){
8635                 this.alignTo(el, alignment, offsets, animate);
8636                 Roo.callback(callback, this);
8637             };
8638             Roo.EventManager.onWindowResize(action, this);
8639             var tm = typeof monitorScroll;
8640             if(tm != 'undefined'){
8641                 Roo.EventManager.on(window, 'scroll', action, this,
8642                     {buffer: tm == 'number' ? monitorScroll : 50});
8643             }
8644             action.call(this); // align immediately
8645             return this;
8646         },
8647         /**
8648          * Clears any opacity settings from this element. Required in some cases for IE.
8649          * @return {Roo.Element} this
8650          */
8651         clearOpacity : function(){
8652             if (window.ActiveXObject) {
8653                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8654                     this.dom.style.filter = "";
8655                 }
8656             } else {
8657                 this.dom.style.opacity = "";
8658                 this.dom.style["-moz-opacity"] = "";
8659                 this.dom.style["-khtml-opacity"] = "";
8660             }
8661             return this;
8662         },
8663
8664         /**
8665          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8666          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8667          * @return {Roo.Element} this
8668          */
8669         hide : function(animate){
8670             this.setVisible(false, this.preanim(arguments, 0));
8671             return this;
8672         },
8673
8674         /**
8675         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8676         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8677          * @return {Roo.Element} this
8678          */
8679         show : function(animate){
8680             this.setVisible(true, this.preanim(arguments, 0));
8681             return this;
8682         },
8683
8684         /**
8685          * @private Test if size has a unit, otherwise appends the default
8686          */
8687         addUnits : function(size){
8688             return Roo.Element.addUnits(size, this.defaultUnit);
8689         },
8690
8691         /**
8692          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8693          * @return {Roo.Element} this
8694          */
8695         beginMeasure : function(){
8696             var el = this.dom;
8697             if(el.offsetWidth || el.offsetHeight){
8698                 return this; // offsets work already
8699             }
8700             var changed = [];
8701             var p = this.dom, b = document.body; // start with this element
8702             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8703                 var pe = Roo.get(p);
8704                 if(pe.getStyle('display') == 'none'){
8705                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8706                     p.style.visibility = "hidden";
8707                     p.style.display = "block";
8708                 }
8709                 p = p.parentNode;
8710             }
8711             this._measureChanged = changed;
8712             return this;
8713
8714         },
8715
8716         /**
8717          * Restores displays to before beginMeasure was called
8718          * @return {Roo.Element} this
8719          */
8720         endMeasure : function(){
8721             var changed = this._measureChanged;
8722             if(changed){
8723                 for(var i = 0, len = changed.length; i < len; i++) {
8724                     var r = changed[i];
8725                     r.el.style.visibility = r.visibility;
8726                     r.el.style.display = "none";
8727                 }
8728                 this._measureChanged = null;
8729             }
8730             return this;
8731         },
8732
8733         /**
8734         * Update the innerHTML of this element, optionally searching for and processing scripts
8735         * @param {String} html The new HTML
8736         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8737         * @param {Function} callback For async script loading you can be noticed when the update completes
8738         * @return {Roo.Element} this
8739          */
8740         update : function(html, loadScripts, callback){
8741             if(typeof html == "undefined"){
8742                 html = "";
8743             }
8744             if(loadScripts !== true){
8745                 this.dom.innerHTML = html;
8746                 if(typeof callback == "function"){
8747                     callback();
8748                 }
8749                 return this;
8750             }
8751             var id = Roo.id();
8752             var dom = this.dom;
8753
8754             html += '<span id="' + id + '"></span>';
8755
8756             E.onAvailable(id, function(){
8757                 var hd = document.getElementsByTagName("head")[0];
8758                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8759                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8760                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8761
8762                 var match;
8763                 while(match = re.exec(html)){
8764                     var attrs = match[1];
8765                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8766                     if(srcMatch && srcMatch[2]){
8767                        var s = document.createElement("script");
8768                        s.src = srcMatch[2];
8769                        var typeMatch = attrs.match(typeRe);
8770                        if(typeMatch && typeMatch[2]){
8771                            s.type = typeMatch[2];
8772                        }
8773                        hd.appendChild(s);
8774                     }else if(match[2] && match[2].length > 0){
8775                         if(window.execScript) {
8776                            window.execScript(match[2]);
8777                         } else {
8778                             /**
8779                              * eval:var:id
8780                              * eval:var:dom
8781                              * eval:var:html
8782                              * 
8783                              */
8784                            window.eval(match[2]);
8785                         }
8786                     }
8787                 }
8788                 var el = document.getElementById(id);
8789                 if(el){el.parentNode.removeChild(el);}
8790                 if(typeof callback == "function"){
8791                     callback();
8792                 }
8793             });
8794             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8795             return this;
8796         },
8797
8798         /**
8799          * Direct access to the UpdateManager update() method (takes the same parameters).
8800          * @param {String/Function} url The url for this request or a function to call to get the url
8801          * @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}
8802          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8803          * @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.
8804          * @return {Roo.Element} this
8805          */
8806         load : function(){
8807             var um = this.getUpdateManager();
8808             um.update.apply(um, arguments);
8809             return this;
8810         },
8811
8812         /**
8813         * Gets this element's UpdateManager
8814         * @return {Roo.UpdateManager} The UpdateManager
8815         */
8816         getUpdateManager : function(){
8817             if(!this.updateManager){
8818                 this.updateManager = new Roo.UpdateManager(this);
8819             }
8820             return this.updateManager;
8821         },
8822
8823         /**
8824          * Disables text selection for this element (normalized across browsers)
8825          * @return {Roo.Element} this
8826          */
8827         unselectable : function(){
8828             this.dom.unselectable = "on";
8829             this.swallowEvent("selectstart", true);
8830             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8831             this.addClass("x-unselectable");
8832             return this;
8833         },
8834
8835         /**
8836         * Calculates the x, y to center this element on the screen
8837         * @return {Array} The x, y values [x, y]
8838         */
8839         getCenterXY : function(){
8840             return this.getAlignToXY(document, 'c-c');
8841         },
8842
8843         /**
8844         * Centers the Element in either the viewport, or another Element.
8845         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8846         */
8847         center : function(centerIn){
8848             this.alignTo(centerIn || document, 'c-c');
8849             return this;
8850         },
8851
8852         /**
8853          * Tests various css rules/browsers to determine if this element uses a border box
8854          * @return {Boolean}
8855          */
8856         isBorderBox : function(){
8857             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8858         },
8859
8860         /**
8861          * Return a box {x, y, width, height} that can be used to set another elements
8862          * size/location to match this element.
8863          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8864          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8865          * @return {Object} box An object in the format {x, y, width, height}
8866          */
8867         getBox : function(contentBox, local){
8868             var xy;
8869             if(!local){
8870                 xy = this.getXY();
8871             }else{
8872                 var left = parseInt(this.getStyle("left"), 10) || 0;
8873                 var top = parseInt(this.getStyle("top"), 10) || 0;
8874                 xy = [left, top];
8875             }
8876             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8877             if(!contentBox){
8878                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8879             }else{
8880                 var l = this.getBorderWidth("l")+this.getPadding("l");
8881                 var r = this.getBorderWidth("r")+this.getPadding("r");
8882                 var t = this.getBorderWidth("t")+this.getPadding("t");
8883                 var b = this.getBorderWidth("b")+this.getPadding("b");
8884                 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)};
8885             }
8886             bx.right = bx.x + bx.width;
8887             bx.bottom = bx.y + bx.height;
8888             return bx;
8889         },
8890
8891         /**
8892          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8893          for more information about the sides.
8894          * @param {String} sides
8895          * @return {Number}
8896          */
8897         getFrameWidth : function(sides, onlyContentBox){
8898             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8899         },
8900
8901         /**
8902          * 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.
8903          * @param {Object} box The box to fill {x, y, width, height}
8904          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8905          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8906          * @return {Roo.Element} this
8907          */
8908         setBox : function(box, adjust, animate){
8909             var w = box.width, h = box.height;
8910             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8911                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8912                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8913             }
8914             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8915             return this;
8916         },
8917
8918         /**
8919          * Forces the browser to repaint this element
8920          * @return {Roo.Element} this
8921          */
8922          repaint : function(){
8923             var dom = this.dom;
8924             this.addClass("x-repaint");
8925             setTimeout(function(){
8926                 Roo.get(dom).removeClass("x-repaint");
8927             }, 1);
8928             return this;
8929         },
8930
8931         /**
8932          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8933          * then it returns the calculated width of the sides (see getPadding)
8934          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8935          * @return {Object/Number}
8936          */
8937         getMargins : function(side){
8938             if(!side){
8939                 return {
8940                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8941                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8942                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8943                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8944                 };
8945             }else{
8946                 return this.addStyles(side, El.margins);
8947              }
8948         },
8949
8950         // private
8951         addStyles : function(sides, styles){
8952             var val = 0, v, w;
8953             for(var i = 0, len = sides.length; i < len; i++){
8954                 v = this.getStyle(styles[sides.charAt(i)]);
8955                 if(v){
8956                      w = parseInt(v, 10);
8957                      if(w){ val += w; }
8958                 }
8959             }
8960             return val;
8961         },
8962
8963         /**
8964          * Creates a proxy element of this element
8965          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8966          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8967          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8968          * @return {Roo.Element} The new proxy element
8969          */
8970         createProxy : function(config, renderTo, matchBox){
8971             if(renderTo){
8972                 renderTo = Roo.getDom(renderTo);
8973             }else{
8974                 renderTo = document.body;
8975             }
8976             config = typeof config == "object" ?
8977                 config : {tag : "div", cls: config};
8978             var proxy = Roo.DomHelper.append(renderTo, config, true);
8979             if(matchBox){
8980                proxy.setBox(this.getBox());
8981             }
8982             return proxy;
8983         },
8984
8985         /**
8986          * Puts a mask over this element to disable user interaction. Requires core.css.
8987          * This method can only be applied to elements which accept child nodes.
8988          * @param {String} msg (optional) A message to display in the mask
8989          * @param {String} msgCls (optional) A css class to apply to the msg element
8990          * @return {Element} The mask  element
8991          */
8992         mask : function(msg, msgCls)
8993         {
8994             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8995                 this.setStyle("position", "relative");
8996             }
8997             if(!this._mask){
8998                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8999             }
9000             this.addClass("x-masked");
9001             this._mask.setDisplayed(true);
9002             
9003             // we wander
9004             var z = 0;
9005             var dom = this.dom
9006             while (dom && dom.style) {
9007                 if (!isNaN(parseInt(dom.style.zIndex))) {
9008                     z = Math.max(z, parseInt(dom.style.zIndex));
9009                 }
9010                 dom = dom.parentNode;
9011             }
9012             // if we are masking the body - then it hides everything..
9013             if (this.dom == document.body) {
9014                 z = 1000000;
9015                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9016                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9017             }
9018            
9019             if(typeof msg == 'string'){
9020                 if(!this._maskMsg){
9021                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9022                 }
9023                 var mm = this._maskMsg;
9024                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9025                 if (mm.dom.firstChild) { // weird IE issue?
9026                     mm.dom.firstChild.innerHTML = msg;
9027                 }
9028                 mm.setDisplayed(true);
9029                 mm.center(this);
9030                 mm.setStyle('z-index', z + 102);
9031             }
9032             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9033                 this._mask.setHeight(this.getHeight());
9034             }
9035             this._mask.setStyle('z-index', z + 100);
9036             
9037             return this._mask;
9038         },
9039
9040         /**
9041          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9042          * it is cached for reuse.
9043          */
9044         unmask : function(removeEl){
9045             if(this._mask){
9046                 if(removeEl === true){
9047                     this._mask.remove();
9048                     delete this._mask;
9049                     if(this._maskMsg){
9050                         this._maskMsg.remove();
9051                         delete this._maskMsg;
9052                     }
9053                 }else{
9054                     this._mask.setDisplayed(false);
9055                     if(this._maskMsg){
9056                         this._maskMsg.setDisplayed(false);
9057                     }
9058                 }
9059             }
9060             this.removeClass("x-masked");
9061         },
9062
9063         /**
9064          * Returns true if this element is masked
9065          * @return {Boolean}
9066          */
9067         isMasked : function(){
9068             return this._mask && this._mask.isVisible();
9069         },
9070
9071         /**
9072          * Creates an iframe shim for this element to keep selects and other windowed objects from
9073          * showing through.
9074          * @return {Roo.Element} The new shim element
9075          */
9076         createShim : function(){
9077             var el = document.createElement('iframe');
9078             el.frameBorder = 'no';
9079             el.className = 'roo-shim';
9080             if(Roo.isIE && Roo.isSecure){
9081                 el.src = Roo.SSL_SECURE_URL;
9082             }
9083             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9084             shim.autoBoxAdjust = false;
9085             return shim;
9086         },
9087
9088         /**
9089          * Removes this element from the DOM and deletes it from the cache
9090          */
9091         remove : function(){
9092             if(this.dom.parentNode){
9093                 this.dom.parentNode.removeChild(this.dom);
9094             }
9095             delete El.cache[this.dom.id];
9096         },
9097
9098         /**
9099          * Sets up event handlers to add and remove a css class when the mouse is over this element
9100          * @param {String} className
9101          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9102          * mouseout events for children elements
9103          * @return {Roo.Element} this
9104          */
9105         addClassOnOver : function(className, preventFlicker){
9106             this.on("mouseover", function(){
9107                 Roo.fly(this, '_internal').addClass(className);
9108             }, this.dom);
9109             var removeFn = function(e){
9110                 if(preventFlicker !== true || !e.within(this, true)){
9111                     Roo.fly(this, '_internal').removeClass(className);
9112                 }
9113             };
9114             this.on("mouseout", removeFn, this.dom);
9115             return this;
9116         },
9117
9118         /**
9119          * Sets up event handlers to add and remove a css class when this element has the focus
9120          * @param {String} className
9121          * @return {Roo.Element} this
9122          */
9123         addClassOnFocus : function(className){
9124             this.on("focus", function(){
9125                 Roo.fly(this, '_internal').addClass(className);
9126             }, this.dom);
9127             this.on("blur", function(){
9128                 Roo.fly(this, '_internal').removeClass(className);
9129             }, this.dom);
9130             return this;
9131         },
9132         /**
9133          * 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)
9134          * @param {String} className
9135          * @return {Roo.Element} this
9136          */
9137         addClassOnClick : function(className){
9138             var dom = this.dom;
9139             this.on("mousedown", function(){
9140                 Roo.fly(dom, '_internal').addClass(className);
9141                 var d = Roo.get(document);
9142                 var fn = function(){
9143                     Roo.fly(dom, '_internal').removeClass(className);
9144                     d.removeListener("mouseup", fn);
9145                 };
9146                 d.on("mouseup", fn);
9147             });
9148             return this;
9149         },
9150
9151         /**
9152          * Stops the specified event from bubbling and optionally prevents the default action
9153          * @param {String} eventName
9154          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9155          * @return {Roo.Element} this
9156          */
9157         swallowEvent : function(eventName, preventDefault){
9158             var fn = function(e){
9159                 e.stopPropagation();
9160                 if(preventDefault){
9161                     e.preventDefault();
9162                 }
9163             };
9164             if(eventName instanceof Array){
9165                 for(var i = 0, len = eventName.length; i < len; i++){
9166                      this.on(eventName[i], fn);
9167                 }
9168                 return this;
9169             }
9170             this.on(eventName, fn);
9171             return this;
9172         },
9173
9174         /**
9175          * @private
9176          */
9177       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9178
9179         /**
9180          * Sizes this element to its parent element's dimensions performing
9181          * neccessary box adjustments.
9182          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9183          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9184          * @return {Roo.Element} this
9185          */
9186         fitToParent : function(monitorResize, targetParent) {
9187           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9188           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9189           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9190             return;
9191           }
9192           var p = Roo.get(targetParent || this.dom.parentNode);
9193           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9194           if (monitorResize === true) {
9195             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9196             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9197           }
9198           return this;
9199         },
9200
9201         /**
9202          * Gets the next sibling, skipping text nodes
9203          * @return {HTMLElement} The next sibling or null
9204          */
9205         getNextSibling : function(){
9206             var n = this.dom.nextSibling;
9207             while(n && n.nodeType != 1){
9208                 n = n.nextSibling;
9209             }
9210             return n;
9211         },
9212
9213         /**
9214          * Gets the previous sibling, skipping text nodes
9215          * @return {HTMLElement} The previous sibling or null
9216          */
9217         getPrevSibling : function(){
9218             var n = this.dom.previousSibling;
9219             while(n && n.nodeType != 1){
9220                 n = n.previousSibling;
9221             }
9222             return n;
9223         },
9224
9225
9226         /**
9227          * Appends the passed element(s) to this element
9228          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9229          * @return {Roo.Element} this
9230          */
9231         appendChild: function(el){
9232             el = Roo.get(el);
9233             el.appendTo(this);
9234             return this;
9235         },
9236
9237         /**
9238          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9239          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9240          * automatically generated with the specified attributes.
9241          * @param {HTMLElement} insertBefore (optional) a child element of this element
9242          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9243          * @return {Roo.Element} The new child element
9244          */
9245         createChild: function(config, insertBefore, returnDom){
9246             config = config || {tag:'div'};
9247             if(insertBefore){
9248                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9249             }
9250             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9251         },
9252
9253         /**
9254          * Appends this element to the passed element
9255          * @param {String/HTMLElement/Element} el The new parent element
9256          * @return {Roo.Element} this
9257          */
9258         appendTo: function(el){
9259             el = Roo.getDom(el);
9260             el.appendChild(this.dom);
9261             return this;
9262         },
9263
9264         /**
9265          * Inserts this element before the passed element in the DOM
9266          * @param {String/HTMLElement/Element} el The element to insert before
9267          * @return {Roo.Element} this
9268          */
9269         insertBefore: function(el){
9270             el = Roo.getDom(el);
9271             el.parentNode.insertBefore(this.dom, el);
9272             return this;
9273         },
9274
9275         /**
9276          * Inserts this element after the passed element in the DOM
9277          * @param {String/HTMLElement/Element} el The element to insert after
9278          * @return {Roo.Element} this
9279          */
9280         insertAfter: function(el){
9281             el = Roo.getDom(el);
9282             el.parentNode.insertBefore(this.dom, el.nextSibling);
9283             return this;
9284         },
9285
9286         /**
9287          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9288          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9289          * @return {Roo.Element} The new child
9290          */
9291         insertFirst: function(el, returnDom){
9292             el = el || {};
9293             if(typeof el == 'object' && !el.nodeType){ // dh config
9294                 return this.createChild(el, this.dom.firstChild, returnDom);
9295             }else{
9296                 el = Roo.getDom(el);
9297                 this.dom.insertBefore(el, this.dom.firstChild);
9298                 return !returnDom ? Roo.get(el) : el;
9299             }
9300         },
9301
9302         /**
9303          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9304          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9305          * @param {String} where (optional) 'before' or 'after' defaults to before
9306          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9307          * @return {Roo.Element} the inserted Element
9308          */
9309         insertSibling: function(el, where, returnDom){
9310             where = where ? where.toLowerCase() : 'before';
9311             el = el || {};
9312             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9313
9314             if(typeof el == 'object' && !el.nodeType){ // dh config
9315                 if(where == 'after' && !this.dom.nextSibling){
9316                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9317                 }else{
9318                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9319                 }
9320
9321             }else{
9322                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9323                             where == 'before' ? this.dom : this.dom.nextSibling);
9324                 if(!returnDom){
9325                     rt = Roo.get(rt);
9326                 }
9327             }
9328             return rt;
9329         },
9330
9331         /**
9332          * Creates and wraps this element with another element
9333          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9334          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9335          * @return {HTMLElement/Element} The newly created wrapper element
9336          */
9337         wrap: function(config, returnDom){
9338             if(!config){
9339                 config = {tag: "div"};
9340             }
9341             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9342             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9343             return newEl;
9344         },
9345
9346         /**
9347          * Replaces the passed element with this element
9348          * @param {String/HTMLElement/Element} el The element to replace
9349          * @return {Roo.Element} this
9350          */
9351         replace: function(el){
9352             el = Roo.get(el);
9353             this.insertBefore(el);
9354             el.remove();
9355             return this;
9356         },
9357
9358         /**
9359          * Inserts an html fragment into this element
9360          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9361          * @param {String} html The HTML fragment
9362          * @param {Boolean} returnEl True to return an Roo.Element
9363          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9364          */
9365         insertHtml : function(where, html, returnEl){
9366             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9367             return returnEl ? Roo.get(el) : el;
9368         },
9369
9370         /**
9371          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9372          * @param {Object} o The object with the attributes
9373          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9374          * @return {Roo.Element} this
9375          */
9376         set : function(o, useSet){
9377             var el = this.dom;
9378             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9379             for(var attr in o){
9380                 if(attr == "style" || typeof o[attr] == "function") continue;
9381                 if(attr=="cls"){
9382                     el.className = o["cls"];
9383                 }else{
9384                     if(useSet) el.setAttribute(attr, o[attr]);
9385                     else el[attr] = o[attr];
9386                 }
9387             }
9388             if(o.style){
9389                 Roo.DomHelper.applyStyles(el, o.style);
9390             }
9391             return this;
9392         },
9393
9394         /**
9395          * Convenience method for constructing a KeyMap
9396          * @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:
9397          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9398          * @param {Function} fn The function to call
9399          * @param {Object} scope (optional) The scope of the function
9400          * @return {Roo.KeyMap} The KeyMap created
9401          */
9402         addKeyListener : function(key, fn, scope){
9403             var config;
9404             if(typeof key != "object" || key instanceof Array){
9405                 config = {
9406                     key: key,
9407                     fn: fn,
9408                     scope: scope
9409                 };
9410             }else{
9411                 config = {
9412                     key : key.key,
9413                     shift : key.shift,
9414                     ctrl : key.ctrl,
9415                     alt : key.alt,
9416                     fn: fn,
9417                     scope: scope
9418                 };
9419             }
9420             return new Roo.KeyMap(this, config);
9421         },
9422
9423         /**
9424          * Creates a KeyMap for this element
9425          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9426          * @return {Roo.KeyMap} The KeyMap created
9427          */
9428         addKeyMap : function(config){
9429             return new Roo.KeyMap(this, config);
9430         },
9431
9432         /**
9433          * Returns true if this element is scrollable.
9434          * @return {Boolean}
9435          */
9436          isScrollable : function(){
9437             var dom = this.dom;
9438             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9439         },
9440
9441         /**
9442          * 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().
9443          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9444          * @param {Number} value The new scroll value
9445          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9446          * @return {Element} this
9447          */
9448
9449         scrollTo : function(side, value, animate){
9450             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9451             if(!animate || !A){
9452                 this.dom[prop] = value;
9453             }else{
9454                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9455                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9456             }
9457             return this;
9458         },
9459
9460         /**
9461          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9462          * within this element's scrollable range.
9463          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9464          * @param {Number} distance How far to scroll the element in pixels
9465          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9466          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9467          * was scrolled as far as it could go.
9468          */
9469          scroll : function(direction, distance, animate){
9470              if(!this.isScrollable()){
9471                  return;
9472              }
9473              var el = this.dom;
9474              var l = el.scrollLeft, t = el.scrollTop;
9475              var w = el.scrollWidth, h = el.scrollHeight;
9476              var cw = el.clientWidth, ch = el.clientHeight;
9477              direction = direction.toLowerCase();
9478              var scrolled = false;
9479              var a = this.preanim(arguments, 2);
9480              switch(direction){
9481                  case "l":
9482                  case "left":
9483                      if(w - l > cw){
9484                          var v = Math.min(l + distance, w-cw);
9485                          this.scrollTo("left", v, a);
9486                          scrolled = true;
9487                      }
9488                      break;
9489                 case "r":
9490                 case "right":
9491                      if(l > 0){
9492                          var v = Math.max(l - distance, 0);
9493                          this.scrollTo("left", v, a);
9494                          scrolled = true;
9495                      }
9496                      break;
9497                 case "t":
9498                 case "top":
9499                 case "up":
9500                      if(t > 0){
9501                          var v = Math.max(t - distance, 0);
9502                          this.scrollTo("top", v, a);
9503                          scrolled = true;
9504                      }
9505                      break;
9506                 case "b":
9507                 case "bottom":
9508                 case "down":
9509                      if(h - t > ch){
9510                          var v = Math.min(t + distance, h-ch);
9511                          this.scrollTo("top", v, a);
9512                          scrolled = true;
9513                      }
9514                      break;
9515              }
9516              return scrolled;
9517         },
9518
9519         /**
9520          * Translates the passed page coordinates into left/top css values for this element
9521          * @param {Number/Array} x The page x or an array containing [x, y]
9522          * @param {Number} y The page y
9523          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9524          */
9525         translatePoints : function(x, y){
9526             if(typeof x == 'object' || x instanceof Array){
9527                 y = x[1]; x = x[0];
9528             }
9529             var p = this.getStyle('position');
9530             var o = this.getXY();
9531
9532             var l = parseInt(this.getStyle('left'), 10);
9533             var t = parseInt(this.getStyle('top'), 10);
9534
9535             if(isNaN(l)){
9536                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9537             }
9538             if(isNaN(t)){
9539                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9540             }
9541
9542             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9543         },
9544
9545         /**
9546          * Returns the current scroll position of the element.
9547          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9548          */
9549         getScroll : function(){
9550             var d = this.dom, doc = document;
9551             if(d == doc || d == doc.body){
9552                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9553                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9554                 return {left: l, top: t};
9555             }else{
9556                 return {left: d.scrollLeft, top: d.scrollTop};
9557             }
9558         },
9559
9560         /**
9561          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9562          * are convert to standard 6 digit hex color.
9563          * @param {String} attr The css attribute
9564          * @param {String} defaultValue The default value to use when a valid color isn't found
9565          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9566          * YUI color anims.
9567          */
9568         getColor : function(attr, defaultValue, prefix){
9569             var v = this.getStyle(attr);
9570             if(!v || v == "transparent" || v == "inherit") {
9571                 return defaultValue;
9572             }
9573             var color = typeof prefix == "undefined" ? "#" : prefix;
9574             if(v.substr(0, 4) == "rgb("){
9575                 var rvs = v.slice(4, v.length -1).split(",");
9576                 for(var i = 0; i < 3; i++){
9577                     var h = parseInt(rvs[i]).toString(16);
9578                     if(h < 16){
9579                         h = "0" + h;
9580                     }
9581                     color += h;
9582                 }
9583             } else {
9584                 if(v.substr(0, 1) == "#"){
9585                     if(v.length == 4) {
9586                         for(var i = 1; i < 4; i++){
9587                             var c = v.charAt(i);
9588                             color +=  c + c;
9589                         }
9590                     }else if(v.length == 7){
9591                         color += v.substr(1);
9592                     }
9593                 }
9594             }
9595             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9596         },
9597
9598         /**
9599          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9600          * gradient background, rounded corners and a 4-way shadow.
9601          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9602          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9603          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9604          * @return {Roo.Element} this
9605          */
9606         boxWrap : function(cls){
9607             cls = cls || 'x-box';
9608             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9609             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9610             return el;
9611         },
9612
9613         /**
9614          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9615          * @param {String} namespace The namespace in which to look for the attribute
9616          * @param {String} name The attribute name
9617          * @return {String} The attribute value
9618          */
9619         getAttributeNS : Roo.isIE ? function(ns, name){
9620             var d = this.dom;
9621             var type = typeof d[ns+":"+name];
9622             if(type != 'undefined' && type != 'unknown'){
9623                 return d[ns+":"+name];
9624             }
9625             return d[name];
9626         } : function(ns, name){
9627             var d = this.dom;
9628             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9629         },
9630         
9631         
9632         /**
9633          * Sets or Returns the value the dom attribute value
9634          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9635          * @param {String} value (optional) The value to set the attribute to
9636          * @return {String} The attribute value
9637          */
9638         attr : function(name){
9639             if (arguments.length > 1) {
9640                 this.dom.setAttribute(name, arguments[1]);
9641                 return arguments[1];
9642             }
9643             if (typeof(name) == 'object') {
9644                 for(var i in name) {
9645                     this.attr(i, name[i]);
9646                 }
9647                 return name;
9648             }
9649             
9650             
9651             if (!this.dom.hasAttribute(name)) {
9652                 return undefined;
9653             }
9654             return this.dom.getAttribute(name);
9655         }
9656         
9657         
9658         
9659     };
9660
9661     var ep = El.prototype;
9662
9663     /**
9664      * Appends an event handler (Shorthand for addListener)
9665      * @param {String}   eventName     The type of event to append
9666      * @param {Function} fn        The method the event invokes
9667      * @param {Object} scope       (optional) The scope (this object) of the fn
9668      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9669      * @method
9670      */
9671     ep.on = ep.addListener;
9672         // backwards compat
9673     ep.mon = ep.addListener;
9674
9675     /**
9676      * Removes an event handler from this element (shorthand for removeListener)
9677      * @param {String} eventName the type of event to remove
9678      * @param {Function} fn the method the event invokes
9679      * @return {Roo.Element} this
9680      * @method
9681      */
9682     ep.un = ep.removeListener;
9683
9684     /**
9685      * true to automatically adjust width and height settings for box-model issues (default to true)
9686      */
9687     ep.autoBoxAdjust = true;
9688
9689     // private
9690     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9691
9692     // private
9693     El.addUnits = function(v, defaultUnit){
9694         if(v === "" || v == "auto"){
9695             return v;
9696         }
9697         if(v === undefined){
9698             return '';
9699         }
9700         if(typeof v == "number" || !El.unitPattern.test(v)){
9701             return v + (defaultUnit || 'px');
9702         }
9703         return v;
9704     };
9705
9706     // special markup used throughout Roo when box wrapping elements
9707     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>';
9708     /**
9709      * Visibility mode constant - Use visibility to hide element
9710      * @static
9711      * @type Number
9712      */
9713     El.VISIBILITY = 1;
9714     /**
9715      * Visibility mode constant - Use display to hide element
9716      * @static
9717      * @type Number
9718      */
9719     El.DISPLAY = 2;
9720
9721     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9722     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9723     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9724
9725
9726
9727     /**
9728      * @private
9729      */
9730     El.cache = {};
9731
9732     var docEl;
9733
9734     /**
9735      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9736      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9737      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9738      * @return {Element} The Element object
9739      * @static
9740      */
9741     El.get = function(el){
9742         var ex, elm, id;
9743         if(!el){ return null; }
9744         if(typeof el == "string"){ // element id
9745             if(!(elm = document.getElementById(el))){
9746                 return null;
9747             }
9748             if(ex = El.cache[el]){
9749                 ex.dom = elm;
9750             }else{
9751                 ex = El.cache[el] = new El(elm);
9752             }
9753             return ex;
9754         }else if(el.tagName){ // dom element
9755             if(!(id = el.id)){
9756                 id = Roo.id(el);
9757             }
9758             if(ex = El.cache[id]){
9759                 ex.dom = el;
9760             }else{
9761                 ex = El.cache[id] = new El(el);
9762             }
9763             return ex;
9764         }else if(el instanceof El){
9765             if(el != docEl){
9766                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9767                                                               // catch case where it hasn't been appended
9768                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9769             }
9770             return el;
9771         }else if(el.isComposite){
9772             return el;
9773         }else if(el instanceof Array){
9774             return El.select(el);
9775         }else if(el == document){
9776             // create a bogus element object representing the document object
9777             if(!docEl){
9778                 var f = function(){};
9779                 f.prototype = El.prototype;
9780                 docEl = new f();
9781                 docEl.dom = document;
9782             }
9783             return docEl;
9784         }
9785         return null;
9786     };
9787
9788     // private
9789     El.uncache = function(el){
9790         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9791             if(a[i]){
9792                 delete El.cache[a[i].id || a[i]];
9793             }
9794         }
9795     };
9796
9797     // private
9798     // Garbage collection - uncache elements/purge listeners on orphaned elements
9799     // so we don't hold a reference and cause the browser to retain them
9800     El.garbageCollect = function(){
9801         if(!Roo.enableGarbageCollector){
9802             clearInterval(El.collectorThread);
9803             return;
9804         }
9805         for(var eid in El.cache){
9806             var el = El.cache[eid], d = el.dom;
9807             // -------------------------------------------------------
9808             // Determining what is garbage:
9809             // -------------------------------------------------------
9810             // !d
9811             // dom node is null, definitely garbage
9812             // -------------------------------------------------------
9813             // !d.parentNode
9814             // no parentNode == direct orphan, definitely garbage
9815             // -------------------------------------------------------
9816             // !d.offsetParent && !document.getElementById(eid)
9817             // display none elements have no offsetParent so we will
9818             // also try to look it up by it's id. However, check
9819             // offsetParent first so we don't do unneeded lookups.
9820             // This enables collection of elements that are not orphans
9821             // directly, but somewhere up the line they have an orphan
9822             // parent.
9823             // -------------------------------------------------------
9824             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9825                 delete El.cache[eid];
9826                 if(d && Roo.enableListenerCollection){
9827                     E.purgeElement(d);
9828                 }
9829             }
9830         }
9831     }
9832     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9833
9834
9835     // dom is optional
9836     El.Flyweight = function(dom){
9837         this.dom = dom;
9838     };
9839     El.Flyweight.prototype = El.prototype;
9840
9841     El._flyweights = {};
9842     /**
9843      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9844      * the dom node can be overwritten by other code.
9845      * @param {String/HTMLElement} el The dom node or id
9846      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9847      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9848      * @static
9849      * @return {Element} The shared Element object
9850      */
9851     El.fly = function(el, named){
9852         named = named || '_global';
9853         el = Roo.getDom(el);
9854         if(!el){
9855             return null;
9856         }
9857         if(!El._flyweights[named]){
9858             El._flyweights[named] = new El.Flyweight();
9859         }
9860         El._flyweights[named].dom = el;
9861         return El._flyweights[named];
9862     };
9863
9864     /**
9865      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9866      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9867      * Shorthand of {@link Roo.Element#get}
9868      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9869      * @return {Element} The Element object
9870      * @member Roo
9871      * @method get
9872      */
9873     Roo.get = El.get;
9874     /**
9875      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9876      * the dom node can be overwritten by other code.
9877      * Shorthand of {@link Roo.Element#fly}
9878      * @param {String/HTMLElement} el The dom node or id
9879      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9880      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9881      * @static
9882      * @return {Element} The shared Element object
9883      * @member Roo
9884      * @method fly
9885      */
9886     Roo.fly = El.fly;
9887
9888     // speedy lookup for elements never to box adjust
9889     var noBoxAdjust = Roo.isStrict ? {
9890         select:1
9891     } : {
9892         input:1, select:1, textarea:1
9893     };
9894     if(Roo.isIE || Roo.isGecko){
9895         noBoxAdjust['button'] = 1;
9896     }
9897
9898
9899     Roo.EventManager.on(window, 'unload', function(){
9900         delete El.cache;
9901         delete El._flyweights;
9902     });
9903 })();
9904
9905
9906
9907
9908 if(Roo.DomQuery){
9909     Roo.Element.selectorFunction = Roo.DomQuery.select;
9910 }
9911
9912 Roo.Element.select = function(selector, unique, root){
9913     var els;
9914     if(typeof selector == "string"){
9915         els = Roo.Element.selectorFunction(selector, root);
9916     }else if(selector.length !== undefined){
9917         els = selector;
9918     }else{
9919         throw "Invalid selector";
9920     }
9921     if(unique === true){
9922         return new Roo.CompositeElement(els);
9923     }else{
9924         return new Roo.CompositeElementLite(els);
9925     }
9926 };
9927 /**
9928  * Selects elements based on the passed CSS selector to enable working on them as 1.
9929  * @param {String/Array} selector The CSS selector or an array of elements
9930  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9931  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9932  * @return {CompositeElementLite/CompositeElement}
9933  * @member Roo
9934  * @method select
9935  */
9936 Roo.select = Roo.Element.select;
9937
9938
9939
9940
9941
9942
9943
9944
9945
9946
9947
9948
9949
9950
9951 /*
9952  * Based on:
9953  * Ext JS Library 1.1.1
9954  * Copyright(c) 2006-2007, Ext JS, LLC.
9955  *
9956  * Originally Released Under LGPL - original licence link has changed is not relivant.
9957  *
9958  * Fork - LGPL
9959  * <script type="text/javascript">
9960  */
9961
9962
9963
9964 //Notifies Element that fx methods are available
9965 Roo.enableFx = true;
9966
9967 /**
9968  * @class Roo.Fx
9969  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9970  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9971  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9972  * Element effects to work.</p><br/>
9973  *
9974  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9975  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9976  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9977  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9978  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9979  * expected results and should be done with care.</p><br/>
9980  *
9981  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9982  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9983 <pre>
9984 Value  Description
9985 -----  -----------------------------
9986 tl     The top left corner
9987 t      The center of the top edge
9988 tr     The top right corner
9989 l      The center of the left edge
9990 r      The center of the right edge
9991 bl     The bottom left corner
9992 b      The center of the bottom edge
9993 br     The bottom right corner
9994 </pre>
9995  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9996  * below are common options that can be passed to any Fx method.</b>
9997  * @cfg {Function} callback A function called when the effect is finished
9998  * @cfg {Object} scope The scope of the effect function
9999  * @cfg {String} easing A valid Easing value for the effect
10000  * @cfg {String} afterCls A css class to apply after the effect
10001  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10002  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10003  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10004  * effects that end with the element being visually hidden, ignored otherwise)
10005  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10006  * a function which returns such a specification that will be applied to the Element after the effect finishes
10007  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10008  * @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
10009  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10010  */
10011 Roo.Fx = {
10012         /**
10013          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10014          * origin for the slide effect.  This function automatically handles wrapping the element with
10015          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10016          * Usage:
10017          *<pre><code>
10018 // default: slide the element in from the top
10019 el.slideIn();
10020
10021 // custom: slide the element in from the right with a 2-second duration
10022 el.slideIn('r', { duration: 2 });
10023
10024 // common config options shown with default values
10025 el.slideIn('t', {
10026     easing: 'easeOut',
10027     duration: .5
10028 });
10029 </code></pre>
10030          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10031          * @param {Object} options (optional) Object literal with any of the Fx config options
10032          * @return {Roo.Element} The Element
10033          */
10034     slideIn : function(anchor, o){
10035         var el = this.getFxEl();
10036         o = o || {};
10037
10038         el.queueFx(o, function(){
10039
10040             anchor = anchor || "t";
10041
10042             // fix display to visibility
10043             this.fixDisplay();
10044
10045             // restore values after effect
10046             var r = this.getFxRestore();
10047             var b = this.getBox();
10048             // fixed size for slide
10049             this.setSize(b);
10050
10051             // wrap if needed
10052             var wrap = this.fxWrap(r.pos, o, "hidden");
10053
10054             var st = this.dom.style;
10055             st.visibility = "visible";
10056             st.position = "absolute";
10057
10058             // clear out temp styles after slide and unwrap
10059             var after = function(){
10060                 el.fxUnwrap(wrap, r.pos, o);
10061                 st.width = r.width;
10062                 st.height = r.height;
10063                 el.afterFx(o);
10064             };
10065             // time to calc the positions
10066             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10067
10068             switch(anchor.toLowerCase()){
10069                 case "t":
10070                     wrap.setSize(b.width, 0);
10071                     st.left = st.bottom = "0";
10072                     a = {height: bh};
10073                 break;
10074                 case "l":
10075                     wrap.setSize(0, b.height);
10076                     st.right = st.top = "0";
10077                     a = {width: bw};
10078                 break;
10079                 case "r":
10080                     wrap.setSize(0, b.height);
10081                     wrap.setX(b.right);
10082                     st.left = st.top = "0";
10083                     a = {width: bw, points: pt};
10084                 break;
10085                 case "b":
10086                     wrap.setSize(b.width, 0);
10087                     wrap.setY(b.bottom);
10088                     st.left = st.top = "0";
10089                     a = {height: bh, points: pt};
10090                 break;
10091                 case "tl":
10092                     wrap.setSize(0, 0);
10093                     st.right = st.bottom = "0";
10094                     a = {width: bw, height: bh};
10095                 break;
10096                 case "bl":
10097                     wrap.setSize(0, 0);
10098                     wrap.setY(b.y+b.height);
10099                     st.right = st.top = "0";
10100                     a = {width: bw, height: bh, points: pt};
10101                 break;
10102                 case "br":
10103                     wrap.setSize(0, 0);
10104                     wrap.setXY([b.right, b.bottom]);
10105                     st.left = st.top = "0";
10106                     a = {width: bw, height: bh, points: pt};
10107                 break;
10108                 case "tr":
10109                     wrap.setSize(0, 0);
10110                     wrap.setX(b.x+b.width);
10111                     st.left = st.bottom = "0";
10112                     a = {width: bw, height: bh, points: pt};
10113                 break;
10114             }
10115             this.dom.style.visibility = "visible";
10116             wrap.show();
10117
10118             arguments.callee.anim = wrap.fxanim(a,
10119                 o,
10120                 'motion',
10121                 .5,
10122                 'easeOut', after);
10123         });
10124         return this;
10125     },
10126     
10127         /**
10128          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10129          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10130          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10131          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10132          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10133          * Usage:
10134          *<pre><code>
10135 // default: slide the element out to the top
10136 el.slideOut();
10137
10138 // custom: slide the element out to the right with a 2-second duration
10139 el.slideOut('r', { duration: 2 });
10140
10141 // common config options shown with default values
10142 el.slideOut('t', {
10143     easing: 'easeOut',
10144     duration: .5,
10145     remove: false,
10146     useDisplay: false
10147 });
10148 </code></pre>
10149          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10150          * @param {Object} options (optional) Object literal with any of the Fx config options
10151          * @return {Roo.Element} The Element
10152          */
10153     slideOut : function(anchor, o){
10154         var el = this.getFxEl();
10155         o = o || {};
10156
10157         el.queueFx(o, function(){
10158
10159             anchor = anchor || "t";
10160
10161             // restore values after effect
10162             var r = this.getFxRestore();
10163             
10164             var b = this.getBox();
10165             // fixed size for slide
10166             this.setSize(b);
10167
10168             // wrap if needed
10169             var wrap = this.fxWrap(r.pos, o, "visible");
10170
10171             var st = this.dom.style;
10172             st.visibility = "visible";
10173             st.position = "absolute";
10174
10175             wrap.setSize(b);
10176
10177             var after = function(){
10178                 if(o.useDisplay){
10179                     el.setDisplayed(false);
10180                 }else{
10181                     el.hide();
10182                 }
10183
10184                 el.fxUnwrap(wrap, r.pos, o);
10185
10186                 st.width = r.width;
10187                 st.height = r.height;
10188
10189                 el.afterFx(o);
10190             };
10191
10192             var a, zero = {to: 0};
10193             switch(anchor.toLowerCase()){
10194                 case "t":
10195                     st.left = st.bottom = "0";
10196                     a = {height: zero};
10197                 break;
10198                 case "l":
10199                     st.right = st.top = "0";
10200                     a = {width: zero};
10201                 break;
10202                 case "r":
10203                     st.left = st.top = "0";
10204                     a = {width: zero, points: {to:[b.right, b.y]}};
10205                 break;
10206                 case "b":
10207                     st.left = st.top = "0";
10208                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10209                 break;
10210                 case "tl":
10211                     st.right = st.bottom = "0";
10212                     a = {width: zero, height: zero};
10213                 break;
10214                 case "bl":
10215                     st.right = st.top = "0";
10216                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10217                 break;
10218                 case "br":
10219                     st.left = st.top = "0";
10220                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10221                 break;
10222                 case "tr":
10223                     st.left = st.bottom = "0";
10224                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10225                 break;
10226             }
10227
10228             arguments.callee.anim = wrap.fxanim(a,
10229                 o,
10230                 'motion',
10231                 .5,
10232                 "easeOut", after);
10233         });
10234         return this;
10235     },
10236
10237         /**
10238          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10239          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10240          * The element must be removed from the DOM using the 'remove' config option if desired.
10241          * Usage:
10242          *<pre><code>
10243 // default
10244 el.puff();
10245
10246 // common config options shown with default values
10247 el.puff({
10248     easing: 'easeOut',
10249     duration: .5,
10250     remove: false,
10251     useDisplay: false
10252 });
10253 </code></pre>
10254          * @param {Object} options (optional) Object literal with any of the Fx config options
10255          * @return {Roo.Element} The Element
10256          */
10257     puff : function(o){
10258         var el = this.getFxEl();
10259         o = o || {};
10260
10261         el.queueFx(o, function(){
10262             this.clearOpacity();
10263             this.show();
10264
10265             // restore values after effect
10266             var r = this.getFxRestore();
10267             var st = this.dom.style;
10268
10269             var after = function(){
10270                 if(o.useDisplay){
10271                     el.setDisplayed(false);
10272                 }else{
10273                     el.hide();
10274                 }
10275
10276                 el.clearOpacity();
10277
10278                 el.setPositioning(r.pos);
10279                 st.width = r.width;
10280                 st.height = r.height;
10281                 st.fontSize = '';
10282                 el.afterFx(o);
10283             };
10284
10285             var width = this.getWidth();
10286             var height = this.getHeight();
10287
10288             arguments.callee.anim = this.fxanim({
10289                     width : {to: this.adjustWidth(width * 2)},
10290                     height : {to: this.adjustHeight(height * 2)},
10291                     points : {by: [-(width * .5), -(height * .5)]},
10292                     opacity : {to: 0},
10293                     fontSize: {to:200, unit: "%"}
10294                 },
10295                 o,
10296                 'motion',
10297                 .5,
10298                 "easeOut", after);
10299         });
10300         return this;
10301     },
10302
10303         /**
10304          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10305          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10306          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10307          * Usage:
10308          *<pre><code>
10309 // default
10310 el.switchOff();
10311
10312 // all config options shown with default values
10313 el.switchOff({
10314     easing: 'easeIn',
10315     duration: .3,
10316     remove: false,
10317     useDisplay: false
10318 });
10319 </code></pre>
10320          * @param {Object} options (optional) Object literal with any of the Fx config options
10321          * @return {Roo.Element} The Element
10322          */
10323     switchOff : function(o){
10324         var el = this.getFxEl();
10325         o = o || {};
10326
10327         el.queueFx(o, function(){
10328             this.clearOpacity();
10329             this.clip();
10330
10331             // restore values after effect
10332             var r = this.getFxRestore();
10333             var st = this.dom.style;
10334
10335             var after = function(){
10336                 if(o.useDisplay){
10337                     el.setDisplayed(false);
10338                 }else{
10339                     el.hide();
10340                 }
10341
10342                 el.clearOpacity();
10343                 el.setPositioning(r.pos);
10344                 st.width = r.width;
10345                 st.height = r.height;
10346
10347                 el.afterFx(o);
10348             };
10349
10350             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10351                 this.clearOpacity();
10352                 (function(){
10353                     this.fxanim({
10354                         height:{to:1},
10355                         points:{by:[0, this.getHeight() * .5]}
10356                     }, o, 'motion', 0.3, 'easeIn', after);
10357                 }).defer(100, this);
10358             });
10359         });
10360         return this;
10361     },
10362
10363     /**
10364      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10365      * changed using the "attr" config option) and then fading back to the original color. If no original
10366      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10367      * Usage:
10368 <pre><code>
10369 // default: highlight background to yellow
10370 el.highlight();
10371
10372 // custom: highlight foreground text to blue for 2 seconds
10373 el.highlight("0000ff", { attr: 'color', duration: 2 });
10374
10375 // common config options shown with default values
10376 el.highlight("ffff9c", {
10377     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10378     endColor: (current color) or "ffffff",
10379     easing: 'easeIn',
10380     duration: 1
10381 });
10382 </code></pre>
10383      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10384      * @param {Object} options (optional) Object literal with any of the Fx config options
10385      * @return {Roo.Element} The Element
10386      */ 
10387     highlight : function(color, o){
10388         var el = this.getFxEl();
10389         o = o || {};
10390
10391         el.queueFx(o, function(){
10392             color = color || "ffff9c";
10393             attr = o.attr || "backgroundColor";
10394
10395             this.clearOpacity();
10396             this.show();
10397
10398             var origColor = this.getColor(attr);
10399             var restoreColor = this.dom.style[attr];
10400             endColor = (o.endColor || origColor) || "ffffff";
10401
10402             var after = function(){
10403                 el.dom.style[attr] = restoreColor;
10404                 el.afterFx(o);
10405             };
10406
10407             var a = {};
10408             a[attr] = {from: color, to: endColor};
10409             arguments.callee.anim = this.fxanim(a,
10410                 o,
10411                 'color',
10412                 1,
10413                 'easeIn', after);
10414         });
10415         return this;
10416     },
10417
10418    /**
10419     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10420     * Usage:
10421 <pre><code>
10422 // default: a single light blue ripple
10423 el.frame();
10424
10425 // custom: 3 red ripples lasting 3 seconds total
10426 el.frame("ff0000", 3, { duration: 3 });
10427
10428 // common config options shown with default values
10429 el.frame("C3DAF9", 1, {
10430     duration: 1 //duration of entire animation (not each individual ripple)
10431     // Note: Easing is not configurable and will be ignored if included
10432 });
10433 </code></pre>
10434     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10435     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10436     * @param {Object} options (optional) Object literal with any of the Fx config options
10437     * @return {Roo.Element} The Element
10438     */
10439     frame : function(color, count, o){
10440         var el = this.getFxEl();
10441         o = o || {};
10442
10443         el.queueFx(o, function(){
10444             color = color || "#C3DAF9";
10445             if(color.length == 6){
10446                 color = "#" + color;
10447             }
10448             count = count || 1;
10449             duration = o.duration || 1;
10450             this.show();
10451
10452             var b = this.getBox();
10453             var animFn = function(){
10454                 var proxy = this.createProxy({
10455
10456                      style:{
10457                         visbility:"hidden",
10458                         position:"absolute",
10459                         "z-index":"35000", // yee haw
10460                         border:"0px solid " + color
10461                      }
10462                   });
10463                 var scale = Roo.isBorderBox ? 2 : 1;
10464                 proxy.animate({
10465                     top:{from:b.y, to:b.y - 20},
10466                     left:{from:b.x, to:b.x - 20},
10467                     borderWidth:{from:0, to:10},
10468                     opacity:{from:1, to:0},
10469                     height:{from:b.height, to:(b.height + (20*scale))},
10470                     width:{from:b.width, to:(b.width + (20*scale))}
10471                 }, duration, function(){
10472                     proxy.remove();
10473                 });
10474                 if(--count > 0){
10475                      animFn.defer((duration/2)*1000, this);
10476                 }else{
10477                     el.afterFx(o);
10478                 }
10479             };
10480             animFn.call(this);
10481         });
10482         return this;
10483     },
10484
10485    /**
10486     * Creates a pause before any subsequent queued effects begin.  If there are
10487     * no effects queued after the pause it will have no effect.
10488     * Usage:
10489 <pre><code>
10490 el.pause(1);
10491 </code></pre>
10492     * @param {Number} seconds The length of time to pause (in seconds)
10493     * @return {Roo.Element} The Element
10494     */
10495     pause : function(seconds){
10496         var el = this.getFxEl();
10497         var o = {};
10498
10499         el.queueFx(o, function(){
10500             setTimeout(function(){
10501                 el.afterFx(o);
10502             }, seconds * 1000);
10503         });
10504         return this;
10505     },
10506
10507    /**
10508     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10509     * using the "endOpacity" config option.
10510     * Usage:
10511 <pre><code>
10512 // default: fade in from opacity 0 to 100%
10513 el.fadeIn();
10514
10515 // custom: fade in from opacity 0 to 75% over 2 seconds
10516 el.fadeIn({ endOpacity: .75, duration: 2});
10517
10518 // common config options shown with default values
10519 el.fadeIn({
10520     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10521     easing: 'easeOut',
10522     duration: .5
10523 });
10524 </code></pre>
10525     * @param {Object} options (optional) Object literal with any of the Fx config options
10526     * @return {Roo.Element} The Element
10527     */
10528     fadeIn : function(o){
10529         var el = this.getFxEl();
10530         o = o || {};
10531         el.queueFx(o, function(){
10532             this.setOpacity(0);
10533             this.fixDisplay();
10534             this.dom.style.visibility = 'visible';
10535             var to = o.endOpacity || 1;
10536             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10537                 o, null, .5, "easeOut", function(){
10538                 if(to == 1){
10539                     this.clearOpacity();
10540                 }
10541                 el.afterFx(o);
10542             });
10543         });
10544         return this;
10545     },
10546
10547    /**
10548     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10549     * using the "endOpacity" config option.
10550     * Usage:
10551 <pre><code>
10552 // default: fade out from the element's current opacity to 0
10553 el.fadeOut();
10554
10555 // custom: fade out from the element's current opacity to 25% over 2 seconds
10556 el.fadeOut({ endOpacity: .25, duration: 2});
10557
10558 // common config options shown with default values
10559 el.fadeOut({
10560     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10561     easing: 'easeOut',
10562     duration: .5
10563     remove: false,
10564     useDisplay: false
10565 });
10566 </code></pre>
10567     * @param {Object} options (optional) Object literal with any of the Fx config options
10568     * @return {Roo.Element} The Element
10569     */
10570     fadeOut : function(o){
10571         var el = this.getFxEl();
10572         o = o || {};
10573         el.queueFx(o, function(){
10574             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10575                 o, null, .5, "easeOut", function(){
10576                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10577                      this.dom.style.display = "none";
10578                 }else{
10579                      this.dom.style.visibility = "hidden";
10580                 }
10581                 this.clearOpacity();
10582                 el.afterFx(o);
10583             });
10584         });
10585         return this;
10586     },
10587
10588    /**
10589     * Animates the transition of an element's dimensions from a starting height/width
10590     * to an ending height/width.
10591     * Usage:
10592 <pre><code>
10593 // change height and width to 100x100 pixels
10594 el.scale(100, 100);
10595
10596 // common config options shown with default values.  The height and width will default to
10597 // the element's existing values if passed as null.
10598 el.scale(
10599     [element's width],
10600     [element's height], {
10601     easing: 'easeOut',
10602     duration: .35
10603 });
10604 </code></pre>
10605     * @param {Number} width  The new width (pass undefined to keep the original width)
10606     * @param {Number} height  The new height (pass undefined to keep the original height)
10607     * @param {Object} options (optional) Object literal with any of the Fx config options
10608     * @return {Roo.Element} The Element
10609     */
10610     scale : function(w, h, o){
10611         this.shift(Roo.apply({}, o, {
10612             width: w,
10613             height: h
10614         }));
10615         return this;
10616     },
10617
10618    /**
10619     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10620     * Any of these properties not specified in the config object will not be changed.  This effect 
10621     * requires that at least one new dimension, position or opacity setting must be passed in on
10622     * the config object in order for the function to have any effect.
10623     * Usage:
10624 <pre><code>
10625 // slide the element horizontally to x position 200 while changing the height and opacity
10626 el.shift({ x: 200, height: 50, opacity: .8 });
10627
10628 // common config options shown with default values.
10629 el.shift({
10630     width: [element's width],
10631     height: [element's height],
10632     x: [element's x position],
10633     y: [element's y position],
10634     opacity: [element's opacity],
10635     easing: 'easeOut',
10636     duration: .35
10637 });
10638 </code></pre>
10639     * @param {Object} options  Object literal with any of the Fx config options
10640     * @return {Roo.Element} The Element
10641     */
10642     shift : function(o){
10643         var el = this.getFxEl();
10644         o = o || {};
10645         el.queueFx(o, function(){
10646             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10647             if(w !== undefined){
10648                 a.width = {to: this.adjustWidth(w)};
10649             }
10650             if(h !== undefined){
10651                 a.height = {to: this.adjustHeight(h)};
10652             }
10653             if(x !== undefined || y !== undefined){
10654                 a.points = {to: [
10655                     x !== undefined ? x : this.getX(),
10656                     y !== undefined ? y : this.getY()
10657                 ]};
10658             }
10659             if(op !== undefined){
10660                 a.opacity = {to: op};
10661             }
10662             if(o.xy !== undefined){
10663                 a.points = {to: o.xy};
10664             }
10665             arguments.callee.anim = this.fxanim(a,
10666                 o, 'motion', .35, "easeOut", function(){
10667                 el.afterFx(o);
10668             });
10669         });
10670         return this;
10671     },
10672
10673         /**
10674          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10675          * ending point of the effect.
10676          * Usage:
10677          *<pre><code>
10678 // default: slide the element downward while fading out
10679 el.ghost();
10680
10681 // custom: slide the element out to the right with a 2-second duration
10682 el.ghost('r', { duration: 2 });
10683
10684 // common config options shown with default values
10685 el.ghost('b', {
10686     easing: 'easeOut',
10687     duration: .5
10688     remove: false,
10689     useDisplay: false
10690 });
10691 </code></pre>
10692          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10693          * @param {Object} options (optional) Object literal with any of the Fx config options
10694          * @return {Roo.Element} The Element
10695          */
10696     ghost : function(anchor, o){
10697         var el = this.getFxEl();
10698         o = o || {};
10699
10700         el.queueFx(o, function(){
10701             anchor = anchor || "b";
10702
10703             // restore values after effect
10704             var r = this.getFxRestore();
10705             var w = this.getWidth(),
10706                 h = this.getHeight();
10707
10708             var st = this.dom.style;
10709
10710             var after = function(){
10711                 if(o.useDisplay){
10712                     el.setDisplayed(false);
10713                 }else{
10714                     el.hide();
10715                 }
10716
10717                 el.clearOpacity();
10718                 el.setPositioning(r.pos);
10719                 st.width = r.width;
10720                 st.height = r.height;
10721
10722                 el.afterFx(o);
10723             };
10724
10725             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10726             switch(anchor.toLowerCase()){
10727                 case "t":
10728                     pt.by = [0, -h];
10729                 break;
10730                 case "l":
10731                     pt.by = [-w, 0];
10732                 break;
10733                 case "r":
10734                     pt.by = [w, 0];
10735                 break;
10736                 case "b":
10737                     pt.by = [0, h];
10738                 break;
10739                 case "tl":
10740                     pt.by = [-w, -h];
10741                 break;
10742                 case "bl":
10743                     pt.by = [-w, h];
10744                 break;
10745                 case "br":
10746                     pt.by = [w, h];
10747                 break;
10748                 case "tr":
10749                     pt.by = [w, -h];
10750                 break;
10751             }
10752
10753             arguments.callee.anim = this.fxanim(a,
10754                 o,
10755                 'motion',
10756                 .5,
10757                 "easeOut", after);
10758         });
10759         return this;
10760     },
10761
10762         /**
10763          * Ensures that all effects queued after syncFx is called on the element are
10764          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10765          * @return {Roo.Element} The Element
10766          */
10767     syncFx : function(){
10768         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10769             block : false,
10770             concurrent : true,
10771             stopFx : false
10772         });
10773         return this;
10774     },
10775
10776         /**
10777          * Ensures that all effects queued after sequenceFx is called on the element are
10778          * run in sequence.  This is the opposite of {@link #syncFx}.
10779          * @return {Roo.Element} The Element
10780          */
10781     sequenceFx : function(){
10782         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10783             block : false,
10784             concurrent : false,
10785             stopFx : false
10786         });
10787         return this;
10788     },
10789
10790         /* @private */
10791     nextFx : function(){
10792         var ef = this.fxQueue[0];
10793         if(ef){
10794             ef.call(this);
10795         }
10796     },
10797
10798         /**
10799          * Returns true if the element has any effects actively running or queued, else returns false.
10800          * @return {Boolean} True if element has active effects, else false
10801          */
10802     hasActiveFx : function(){
10803         return this.fxQueue && this.fxQueue[0];
10804     },
10805
10806         /**
10807          * Stops any running effects and clears the element's internal effects queue if it contains
10808          * any additional effects that haven't started yet.
10809          * @return {Roo.Element} The Element
10810          */
10811     stopFx : function(){
10812         if(this.hasActiveFx()){
10813             var cur = this.fxQueue[0];
10814             if(cur && cur.anim && cur.anim.isAnimated()){
10815                 this.fxQueue = [cur]; // clear out others
10816                 cur.anim.stop(true);
10817             }
10818         }
10819         return this;
10820     },
10821
10822         /* @private */
10823     beforeFx : function(o){
10824         if(this.hasActiveFx() && !o.concurrent){
10825            if(o.stopFx){
10826                this.stopFx();
10827                return true;
10828            }
10829            return false;
10830         }
10831         return true;
10832     },
10833
10834         /**
10835          * Returns true if the element is currently blocking so that no other effect can be queued
10836          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10837          * used to ensure that an effect initiated by a user action runs to completion prior to the
10838          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10839          * @return {Boolean} True if blocking, else false
10840          */
10841     hasFxBlock : function(){
10842         var q = this.fxQueue;
10843         return q && q[0] && q[0].block;
10844     },
10845
10846         /* @private */
10847     queueFx : function(o, fn){
10848         if(!this.fxQueue){
10849             this.fxQueue = [];
10850         }
10851         if(!this.hasFxBlock()){
10852             Roo.applyIf(o, this.fxDefaults);
10853             if(!o.concurrent){
10854                 var run = this.beforeFx(o);
10855                 fn.block = o.block;
10856                 this.fxQueue.push(fn);
10857                 if(run){
10858                     this.nextFx();
10859                 }
10860             }else{
10861                 fn.call(this);
10862             }
10863         }
10864         return this;
10865     },
10866
10867         /* @private */
10868     fxWrap : function(pos, o, vis){
10869         var wrap;
10870         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10871             var wrapXY;
10872             if(o.fixPosition){
10873                 wrapXY = this.getXY();
10874             }
10875             var div = document.createElement("div");
10876             div.style.visibility = vis;
10877             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10878             wrap.setPositioning(pos);
10879             if(wrap.getStyle("position") == "static"){
10880                 wrap.position("relative");
10881             }
10882             this.clearPositioning('auto');
10883             wrap.clip();
10884             wrap.dom.appendChild(this.dom);
10885             if(wrapXY){
10886                 wrap.setXY(wrapXY);
10887             }
10888         }
10889         return wrap;
10890     },
10891
10892         /* @private */
10893     fxUnwrap : function(wrap, pos, o){
10894         this.clearPositioning();
10895         this.setPositioning(pos);
10896         if(!o.wrap){
10897             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10898             wrap.remove();
10899         }
10900     },
10901
10902         /* @private */
10903     getFxRestore : function(){
10904         var st = this.dom.style;
10905         return {pos: this.getPositioning(), width: st.width, height : st.height};
10906     },
10907
10908         /* @private */
10909     afterFx : function(o){
10910         if(o.afterStyle){
10911             this.applyStyles(o.afterStyle);
10912         }
10913         if(o.afterCls){
10914             this.addClass(o.afterCls);
10915         }
10916         if(o.remove === true){
10917             this.remove();
10918         }
10919         Roo.callback(o.callback, o.scope, [this]);
10920         if(!o.concurrent){
10921             this.fxQueue.shift();
10922             this.nextFx();
10923         }
10924     },
10925
10926         /* @private */
10927     getFxEl : function(){ // support for composite element fx
10928         return Roo.get(this.dom);
10929     },
10930
10931         /* @private */
10932     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10933         animType = animType || 'run';
10934         opt = opt || {};
10935         var anim = Roo.lib.Anim[animType](
10936             this.dom, args,
10937             (opt.duration || defaultDur) || .35,
10938             (opt.easing || defaultEase) || 'easeOut',
10939             function(){
10940                 Roo.callback(cb, this);
10941             },
10942             this
10943         );
10944         opt.anim = anim;
10945         return anim;
10946     }
10947 };
10948
10949 // backwords compat
10950 Roo.Fx.resize = Roo.Fx.scale;
10951
10952 //When included, Roo.Fx is automatically applied to Element so that all basic
10953 //effects are available directly via the Element API
10954 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10955  * Based on:
10956  * Ext JS Library 1.1.1
10957  * Copyright(c) 2006-2007, Ext JS, LLC.
10958  *
10959  * Originally Released Under LGPL - original licence link has changed is not relivant.
10960  *
10961  * Fork - LGPL
10962  * <script type="text/javascript">
10963  */
10964
10965
10966 /**
10967  * @class Roo.CompositeElement
10968  * Standard composite class. Creates a Roo.Element for every element in the collection.
10969  * <br><br>
10970  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10971  * actions will be performed on all the elements in this collection.</b>
10972  * <br><br>
10973  * All methods return <i>this</i> and can be chained.
10974  <pre><code>
10975  var els = Roo.select("#some-el div.some-class", true);
10976  // or select directly from an existing element
10977  var el = Roo.get('some-el');
10978  el.select('div.some-class', true);
10979
10980  els.setWidth(100); // all elements become 100 width
10981  els.hide(true); // all elements fade out and hide
10982  // or
10983  els.setWidth(100).hide(true);
10984  </code></pre>
10985  */
10986 Roo.CompositeElement = function(els){
10987     this.elements = [];
10988     this.addElements(els);
10989 };
10990 Roo.CompositeElement.prototype = {
10991     isComposite: true,
10992     addElements : function(els){
10993         if(!els) return this;
10994         if(typeof els == "string"){
10995             els = Roo.Element.selectorFunction(els);
10996         }
10997         var yels = this.elements;
10998         var index = yels.length-1;
10999         for(var i = 0, len = els.length; i < len; i++) {
11000                 yels[++index] = Roo.get(els[i]);
11001         }
11002         return this;
11003     },
11004
11005     /**
11006     * Clears this composite and adds the elements returned by the passed selector.
11007     * @param {String/Array} els A string CSS selector, an array of elements or an element
11008     * @return {CompositeElement} this
11009     */
11010     fill : function(els){
11011         this.elements = [];
11012         this.add(els);
11013         return this;
11014     },
11015
11016     /**
11017     * Filters this composite to only elements that match the passed selector.
11018     * @param {String} selector A string CSS selector
11019     * @param {Boolean} inverse return inverse filter (not matches)
11020     * @return {CompositeElement} this
11021     */
11022     filter : function(selector, inverse){
11023         var els = [];
11024         inverse = inverse || false;
11025         this.each(function(el){
11026             var match = inverse ? !el.is(selector) : el.is(selector);
11027             if(match){
11028                 els[els.length] = el.dom;
11029             }
11030         });
11031         this.fill(els);
11032         return this;
11033     },
11034
11035     invoke : function(fn, args){
11036         var els = this.elements;
11037         for(var i = 0, len = els.length; i < len; i++) {
11038                 Roo.Element.prototype[fn].apply(els[i], args);
11039         }
11040         return this;
11041     },
11042     /**
11043     * Adds elements to this composite.
11044     * @param {String/Array} els A string CSS selector, an array of elements or an element
11045     * @return {CompositeElement} this
11046     */
11047     add : function(els){
11048         if(typeof els == "string"){
11049             this.addElements(Roo.Element.selectorFunction(els));
11050         }else if(els.length !== undefined){
11051             this.addElements(els);
11052         }else{
11053             this.addElements([els]);
11054         }
11055         return this;
11056     },
11057     /**
11058     * Calls the passed function passing (el, this, index) for each element in this composite.
11059     * @param {Function} fn The function to call
11060     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11061     * @return {CompositeElement} this
11062     */
11063     each : function(fn, scope){
11064         var els = this.elements;
11065         for(var i = 0, len = els.length; i < len; i++){
11066             if(fn.call(scope || els[i], els[i], this, i) === false) {
11067                 break;
11068             }
11069         }
11070         return this;
11071     },
11072
11073     /**
11074      * Returns the Element object at the specified index
11075      * @param {Number} index
11076      * @return {Roo.Element}
11077      */
11078     item : function(index){
11079         return this.elements[index] || null;
11080     },
11081
11082     /**
11083      * Returns the first Element
11084      * @return {Roo.Element}
11085      */
11086     first : function(){
11087         return this.item(0);
11088     },
11089
11090     /**
11091      * Returns the last Element
11092      * @return {Roo.Element}
11093      */
11094     last : function(){
11095         return this.item(this.elements.length-1);
11096     },
11097
11098     /**
11099      * Returns the number of elements in this composite
11100      * @return Number
11101      */
11102     getCount : function(){
11103         return this.elements.length;
11104     },
11105
11106     /**
11107      * Returns true if this composite contains the passed element
11108      * @return Boolean
11109      */
11110     contains : function(el){
11111         return this.indexOf(el) !== -1;
11112     },
11113
11114     /**
11115      * Returns true if this composite contains the passed element
11116      * @return Boolean
11117      */
11118     indexOf : function(el){
11119         return this.elements.indexOf(Roo.get(el));
11120     },
11121
11122
11123     /**
11124     * Removes the specified element(s).
11125     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11126     * or an array of any of those.
11127     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11128     * @return {CompositeElement} this
11129     */
11130     removeElement : function(el, removeDom){
11131         if(el instanceof Array){
11132             for(var i = 0, len = el.length; i < len; i++){
11133                 this.removeElement(el[i]);
11134             }
11135             return this;
11136         }
11137         var index = typeof el == 'number' ? el : this.indexOf(el);
11138         if(index !== -1){
11139             if(removeDom){
11140                 var d = this.elements[index];
11141                 if(d.dom){
11142                     d.remove();
11143                 }else{
11144                     d.parentNode.removeChild(d);
11145                 }
11146             }
11147             this.elements.splice(index, 1);
11148         }
11149         return this;
11150     },
11151
11152     /**
11153     * Replaces the specified element with the passed element.
11154     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11155     * to replace.
11156     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11157     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11158     * @return {CompositeElement} this
11159     */
11160     replaceElement : function(el, replacement, domReplace){
11161         var index = typeof el == 'number' ? el : this.indexOf(el);
11162         if(index !== -1){
11163             if(domReplace){
11164                 this.elements[index].replaceWith(replacement);
11165             }else{
11166                 this.elements.splice(index, 1, Roo.get(replacement))
11167             }
11168         }
11169         return this;
11170     },
11171
11172     /**
11173      * Removes all elements.
11174      */
11175     clear : function(){
11176         this.elements = [];
11177     }
11178 };
11179 (function(){
11180     Roo.CompositeElement.createCall = function(proto, fnName){
11181         if(!proto[fnName]){
11182             proto[fnName] = function(){
11183                 return this.invoke(fnName, arguments);
11184             };
11185         }
11186     };
11187     for(var fnName in Roo.Element.prototype){
11188         if(typeof Roo.Element.prototype[fnName] == "function"){
11189             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11190         }
11191     };
11192 })();
11193 /*
11194  * Based on:
11195  * Ext JS Library 1.1.1
11196  * Copyright(c) 2006-2007, Ext JS, LLC.
11197  *
11198  * Originally Released Under LGPL - original licence link has changed is not relivant.
11199  *
11200  * Fork - LGPL
11201  * <script type="text/javascript">
11202  */
11203
11204 /**
11205  * @class Roo.CompositeElementLite
11206  * @extends Roo.CompositeElement
11207  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11208  <pre><code>
11209  var els = Roo.select("#some-el div.some-class");
11210  // or select directly from an existing element
11211  var el = Roo.get('some-el');
11212  el.select('div.some-class');
11213
11214  els.setWidth(100); // all elements become 100 width
11215  els.hide(true); // all elements fade out and hide
11216  // or
11217  els.setWidth(100).hide(true);
11218  </code></pre><br><br>
11219  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11220  * actions will be performed on all the elements in this collection.</b>
11221  */
11222 Roo.CompositeElementLite = function(els){
11223     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11224     this.el = new Roo.Element.Flyweight();
11225 };
11226 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11227     addElements : function(els){
11228         if(els){
11229             if(els instanceof Array){
11230                 this.elements = this.elements.concat(els);
11231             }else{
11232                 var yels = this.elements;
11233                 var index = yels.length-1;
11234                 for(var i = 0, len = els.length; i < len; i++) {
11235                     yels[++index] = els[i];
11236                 }
11237             }
11238         }
11239         return this;
11240     },
11241     invoke : function(fn, args){
11242         var els = this.elements;
11243         var el = this.el;
11244         for(var i = 0, len = els.length; i < len; i++) {
11245             el.dom = els[i];
11246                 Roo.Element.prototype[fn].apply(el, args);
11247         }
11248         return this;
11249     },
11250     /**
11251      * Returns a flyweight Element of the dom element object at the specified index
11252      * @param {Number} index
11253      * @return {Roo.Element}
11254      */
11255     item : function(index){
11256         if(!this.elements[index]){
11257             return null;
11258         }
11259         this.el.dom = this.elements[index];
11260         return this.el;
11261     },
11262
11263     // fixes scope with flyweight
11264     addListener : function(eventName, handler, scope, opt){
11265         var els = this.elements;
11266         for(var i = 0, len = els.length; i < len; i++) {
11267             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11268         }
11269         return this;
11270     },
11271
11272     /**
11273     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11274     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11275     * a reference to the dom node, use el.dom.</b>
11276     * @param {Function} fn The function to call
11277     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11278     * @return {CompositeElement} this
11279     */
11280     each : function(fn, scope){
11281         var els = this.elements;
11282         var el = this.el;
11283         for(var i = 0, len = els.length; i < len; i++){
11284             el.dom = els[i];
11285                 if(fn.call(scope || el, el, this, i) === false){
11286                 break;
11287             }
11288         }
11289         return this;
11290     },
11291
11292     indexOf : function(el){
11293         return this.elements.indexOf(Roo.getDom(el));
11294     },
11295
11296     replaceElement : function(el, replacement, domReplace){
11297         var index = typeof el == 'number' ? el : this.indexOf(el);
11298         if(index !== -1){
11299             replacement = Roo.getDom(replacement);
11300             if(domReplace){
11301                 var d = this.elements[index];
11302                 d.parentNode.insertBefore(replacement, d);
11303                 d.parentNode.removeChild(d);
11304             }
11305             this.elements.splice(index, 1, replacement);
11306         }
11307         return this;
11308     }
11309 });
11310 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11311
11312 /*
11313  * Based on:
11314  * Ext JS Library 1.1.1
11315  * Copyright(c) 2006-2007, Ext JS, LLC.
11316  *
11317  * Originally Released Under LGPL - original licence link has changed is not relivant.
11318  *
11319  * Fork - LGPL
11320  * <script type="text/javascript">
11321  */
11322
11323  
11324
11325 /**
11326  * @class Roo.data.Connection
11327  * @extends Roo.util.Observable
11328  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11329  * either to a configured URL, or to a URL specified at request time.<br><br>
11330  * <p>
11331  * Requests made by this class are asynchronous, and will return immediately. No data from
11332  * the server will be available to the statement immediately following the {@link #request} call.
11333  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11334  * <p>
11335  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11336  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11337  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11338  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11339  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11340  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11341  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11342  * standard DOM methods.
11343  * @constructor
11344  * @param {Object} config a configuration object.
11345  */
11346 Roo.data.Connection = function(config){
11347     Roo.apply(this, config);
11348     this.addEvents({
11349         /**
11350          * @event beforerequest
11351          * Fires before a network request is made to retrieve a data object.
11352          * @param {Connection} conn This Connection object.
11353          * @param {Object} options The options config object passed to the {@link #request} method.
11354          */
11355         "beforerequest" : true,
11356         /**
11357          * @event requestcomplete
11358          * Fires if the request was successfully completed.
11359          * @param {Connection} conn This Connection object.
11360          * @param {Object} response The XHR object containing the response data.
11361          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11362          * @param {Object} options The options config object passed to the {@link #request} method.
11363          */
11364         "requestcomplete" : true,
11365         /**
11366          * @event requestexception
11367          * Fires if an error HTTP status was returned from the server.
11368          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11369          * @param {Connection} conn This Connection object.
11370          * @param {Object} response The XHR object containing the response data.
11371          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11372          * @param {Object} options The options config object passed to the {@link #request} method.
11373          */
11374         "requestexception" : true
11375     });
11376     Roo.data.Connection.superclass.constructor.call(this);
11377 };
11378
11379 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11380     /**
11381      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11382      */
11383     /**
11384      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11385      * extra parameters to each request made by this object. (defaults to undefined)
11386      */
11387     /**
11388      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11389      *  to each request made by this object. (defaults to undefined)
11390      */
11391     /**
11392      * @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)
11393      */
11394     /**
11395      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11396      */
11397     timeout : 30000,
11398     /**
11399      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11400      * @type Boolean
11401      */
11402     autoAbort:false,
11403
11404     /**
11405      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11406      * @type Boolean
11407      */
11408     disableCaching: true,
11409
11410     /**
11411      * Sends an HTTP request to a remote server.
11412      * @param {Object} options An object which may contain the following properties:<ul>
11413      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11414      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11415      * request, a url encoded string or a function to call to get either.</li>
11416      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11417      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11418      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11419      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11420      * <li>options {Object} The parameter to the request call.</li>
11421      * <li>success {Boolean} True if the request succeeded.</li>
11422      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11423      * </ul></li>
11424      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11425      * The callback is passed the following parameters:<ul>
11426      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11427      * <li>options {Object} The parameter to the request call.</li>
11428      * </ul></li>
11429      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11430      * The callback is passed the following parameters:<ul>
11431      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11432      * <li>options {Object} The parameter to the request call.</li>
11433      * </ul></li>
11434      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11435      * for the callback function. Defaults to the browser window.</li>
11436      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11437      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11438      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11439      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11440      * params for the post data. Any params will be appended to the URL.</li>
11441      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11442      * </ul>
11443      * @return {Number} transactionId
11444      */
11445     request : function(o){
11446         if(this.fireEvent("beforerequest", this, o) !== false){
11447             var p = o.params;
11448
11449             if(typeof p == "function"){
11450                 p = p.call(o.scope||window, o);
11451             }
11452             if(typeof p == "object"){
11453                 p = Roo.urlEncode(o.params);
11454             }
11455             if(this.extraParams){
11456                 var extras = Roo.urlEncode(this.extraParams);
11457                 p = p ? (p + '&' + extras) : extras;
11458             }
11459
11460             var url = o.url || this.url;
11461             if(typeof url == 'function'){
11462                 url = url.call(o.scope||window, o);
11463             }
11464
11465             if(o.form){
11466                 var form = Roo.getDom(o.form);
11467                 url = url || form.action;
11468
11469                 var enctype = form.getAttribute("enctype");
11470                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11471                     return this.doFormUpload(o, p, url);
11472                 }
11473                 var f = Roo.lib.Ajax.serializeForm(form);
11474                 p = p ? (p + '&' + f) : f;
11475             }
11476
11477             var hs = o.headers;
11478             if(this.defaultHeaders){
11479                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11480                 if(!o.headers){
11481                     o.headers = hs;
11482                 }
11483             }
11484
11485             var cb = {
11486                 success: this.handleResponse,
11487                 failure: this.handleFailure,
11488                 scope: this,
11489                 argument: {options: o},
11490                 timeout : o.timeout || this.timeout
11491             };
11492
11493             var method = o.method||this.method||(p ? "POST" : "GET");
11494
11495             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11496                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11497             }
11498
11499             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11500                 if(o.autoAbort){
11501                     this.abort();
11502                 }
11503             }else if(this.autoAbort !== false){
11504                 this.abort();
11505             }
11506
11507             if((method == 'GET' && p) || o.xmlData){
11508                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11509                 p = '';
11510             }
11511             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11512             return this.transId;
11513         }else{
11514             Roo.callback(o.callback, o.scope, [o, null, null]);
11515             return null;
11516         }
11517     },
11518
11519     /**
11520      * Determine whether this object has a request outstanding.
11521      * @param {Number} transactionId (Optional) defaults to the last transaction
11522      * @return {Boolean} True if there is an outstanding request.
11523      */
11524     isLoading : function(transId){
11525         if(transId){
11526             return Roo.lib.Ajax.isCallInProgress(transId);
11527         }else{
11528             return this.transId ? true : false;
11529         }
11530     },
11531
11532     /**
11533      * Aborts any outstanding request.
11534      * @param {Number} transactionId (Optional) defaults to the last transaction
11535      */
11536     abort : function(transId){
11537         if(transId || this.isLoading()){
11538             Roo.lib.Ajax.abort(transId || this.transId);
11539         }
11540     },
11541
11542     // private
11543     handleResponse : function(response){
11544         this.transId = false;
11545         var options = response.argument.options;
11546         response.argument = options ? options.argument : null;
11547         this.fireEvent("requestcomplete", this, response, options);
11548         Roo.callback(options.success, options.scope, [response, options]);
11549         Roo.callback(options.callback, options.scope, [options, true, response]);
11550     },
11551
11552     // private
11553     handleFailure : function(response, e){
11554         this.transId = false;
11555         var options = response.argument.options;
11556         response.argument = options ? options.argument : null;
11557         this.fireEvent("requestexception", this, response, options, e);
11558         Roo.callback(options.failure, options.scope, [response, options]);
11559         Roo.callback(options.callback, options.scope, [options, false, response]);
11560     },
11561
11562     // private
11563     doFormUpload : function(o, ps, url){
11564         var id = Roo.id();
11565         var frame = document.createElement('iframe');
11566         frame.id = id;
11567         frame.name = id;
11568         frame.className = 'x-hidden';
11569         if(Roo.isIE){
11570             frame.src = Roo.SSL_SECURE_URL;
11571         }
11572         document.body.appendChild(frame);
11573
11574         if(Roo.isIE){
11575            document.frames[id].name = id;
11576         }
11577
11578         var form = Roo.getDom(o.form);
11579         form.target = id;
11580         form.method = 'POST';
11581         form.enctype = form.encoding = 'multipart/form-data';
11582         if(url){
11583             form.action = url;
11584         }
11585
11586         var hiddens, hd;
11587         if(ps){ // add dynamic params
11588             hiddens = [];
11589             ps = Roo.urlDecode(ps, false);
11590             for(var k in ps){
11591                 if(ps.hasOwnProperty(k)){
11592                     hd = document.createElement('input');
11593                     hd.type = 'hidden';
11594                     hd.name = k;
11595                     hd.value = ps[k];
11596                     form.appendChild(hd);
11597                     hiddens.push(hd);
11598                 }
11599             }
11600         }
11601
11602         function cb(){
11603             var r = {  // bogus response object
11604                 responseText : '',
11605                 responseXML : null
11606             };
11607
11608             r.argument = o ? o.argument : null;
11609
11610             try { //
11611                 var doc;
11612                 if(Roo.isIE){
11613                     doc = frame.contentWindow.document;
11614                 }else {
11615                     doc = (frame.contentDocument || window.frames[id].document);
11616                 }
11617                 if(doc && doc.body){
11618                     r.responseText = doc.body.innerHTML;
11619                 }
11620                 if(doc && doc.XMLDocument){
11621                     r.responseXML = doc.XMLDocument;
11622                 }else {
11623                     r.responseXML = doc;
11624                 }
11625             }
11626             catch(e) {
11627                 // ignore
11628             }
11629
11630             Roo.EventManager.removeListener(frame, 'load', cb, this);
11631
11632             this.fireEvent("requestcomplete", this, r, o);
11633             Roo.callback(o.success, o.scope, [r, o]);
11634             Roo.callback(o.callback, o.scope, [o, true, r]);
11635
11636             setTimeout(function(){document.body.removeChild(frame);}, 100);
11637         }
11638
11639         Roo.EventManager.on(frame, 'load', cb, this);
11640         form.submit();
11641
11642         if(hiddens){ // remove dynamic params
11643             for(var i = 0, len = hiddens.length; i < len; i++){
11644                 form.removeChild(hiddens[i]);
11645             }
11646         }
11647     }
11648 });
11649 /*
11650  * Based on:
11651  * Ext JS Library 1.1.1
11652  * Copyright(c) 2006-2007, Ext JS, LLC.
11653  *
11654  * Originally Released Under LGPL - original licence link has changed is not relivant.
11655  *
11656  * Fork - LGPL
11657  * <script type="text/javascript">
11658  */
11659  
11660 /**
11661  * Global Ajax request class.
11662  * 
11663  * @class Roo.Ajax
11664  * @extends Roo.data.Connection
11665  * @static
11666  * 
11667  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11668  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11669  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11670  * @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)
11671  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11672  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11673  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11674  */
11675 Roo.Ajax = new Roo.data.Connection({
11676     // fix up the docs
11677     /**
11678      * @scope Roo.Ajax
11679      * @type {Boolear} 
11680      */
11681     autoAbort : false,
11682
11683     /**
11684      * Serialize the passed form into a url encoded string
11685      * @scope Roo.Ajax
11686      * @param {String/HTMLElement} form
11687      * @return {String}
11688      */
11689     serializeForm : function(form){
11690         return Roo.lib.Ajax.serializeForm(form);
11691     }
11692 });/*
11693  * Based on:
11694  * Ext JS Library 1.1.1
11695  * Copyright(c) 2006-2007, Ext JS, LLC.
11696  *
11697  * Originally Released Under LGPL - original licence link has changed is not relivant.
11698  *
11699  * Fork - LGPL
11700  * <script type="text/javascript">
11701  */
11702
11703  
11704 /**
11705  * @class Roo.UpdateManager
11706  * @extends Roo.util.Observable
11707  * Provides AJAX-style update for Element object.<br><br>
11708  * Usage:<br>
11709  * <pre><code>
11710  * // Get it from a Roo.Element object
11711  * var el = Roo.get("foo");
11712  * var mgr = el.getUpdateManager();
11713  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11714  * ...
11715  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11716  * <br>
11717  * // or directly (returns the same UpdateManager instance)
11718  * var mgr = new Roo.UpdateManager("myElementId");
11719  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11720  * mgr.on("update", myFcnNeedsToKnow);
11721  * <br>
11722    // short handed call directly from the element object
11723    Roo.get("foo").load({
11724         url: "bar.php",
11725         scripts:true,
11726         params: "for=bar",
11727         text: "Loading Foo..."
11728    });
11729  * </code></pre>
11730  * @constructor
11731  * Create new UpdateManager directly.
11732  * @param {String/HTMLElement/Roo.Element} el The element to update
11733  * @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).
11734  */
11735 Roo.UpdateManager = function(el, forceNew){
11736     el = Roo.get(el);
11737     if(!forceNew && el.updateManager){
11738         return el.updateManager;
11739     }
11740     /**
11741      * The Element object
11742      * @type Roo.Element
11743      */
11744     this.el = el;
11745     /**
11746      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11747      * @type String
11748      */
11749     this.defaultUrl = null;
11750
11751     this.addEvents({
11752         /**
11753          * @event beforeupdate
11754          * Fired before an update is made, return false from your handler and the update is cancelled.
11755          * @param {Roo.Element} el
11756          * @param {String/Object/Function} url
11757          * @param {String/Object} params
11758          */
11759         "beforeupdate": true,
11760         /**
11761          * @event update
11762          * Fired after successful update is made.
11763          * @param {Roo.Element} el
11764          * @param {Object} oResponseObject The response Object
11765          */
11766         "update": true,
11767         /**
11768          * @event failure
11769          * Fired on update failure.
11770          * @param {Roo.Element} el
11771          * @param {Object} oResponseObject The response Object
11772          */
11773         "failure": true
11774     });
11775     var d = Roo.UpdateManager.defaults;
11776     /**
11777      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11778      * @type String
11779      */
11780     this.sslBlankUrl = d.sslBlankUrl;
11781     /**
11782      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11783      * @type Boolean
11784      */
11785     this.disableCaching = d.disableCaching;
11786     /**
11787      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11788      * @type String
11789      */
11790     this.indicatorText = d.indicatorText;
11791     /**
11792      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11793      * @type String
11794      */
11795     this.showLoadIndicator = d.showLoadIndicator;
11796     /**
11797      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11798      * @type Number
11799      */
11800     this.timeout = d.timeout;
11801
11802     /**
11803      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11804      * @type Boolean
11805      */
11806     this.loadScripts = d.loadScripts;
11807
11808     /**
11809      * Transaction object of current executing transaction
11810      */
11811     this.transaction = null;
11812
11813     /**
11814      * @private
11815      */
11816     this.autoRefreshProcId = null;
11817     /**
11818      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11819      * @type Function
11820      */
11821     this.refreshDelegate = this.refresh.createDelegate(this);
11822     /**
11823      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11824      * @type Function
11825      */
11826     this.updateDelegate = this.update.createDelegate(this);
11827     /**
11828      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11829      * @type Function
11830      */
11831     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11832     /**
11833      * @private
11834      */
11835     this.successDelegate = this.processSuccess.createDelegate(this);
11836     /**
11837      * @private
11838      */
11839     this.failureDelegate = this.processFailure.createDelegate(this);
11840
11841     if(!this.renderer){
11842      /**
11843       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11844       */
11845     this.renderer = new Roo.UpdateManager.BasicRenderer();
11846     }
11847     
11848     Roo.UpdateManager.superclass.constructor.call(this);
11849 };
11850
11851 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11852     /**
11853      * Get the Element this UpdateManager is bound to
11854      * @return {Roo.Element} The element
11855      */
11856     getEl : function(){
11857         return this.el;
11858     },
11859     /**
11860      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11861      * @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:
11862 <pre><code>
11863 um.update({<br/>
11864     url: "your-url.php",<br/>
11865     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11866     callback: yourFunction,<br/>
11867     scope: yourObject, //(optional scope)  <br/>
11868     discardUrl: false, <br/>
11869     nocache: false,<br/>
11870     text: "Loading...",<br/>
11871     timeout: 30,<br/>
11872     scripts: false<br/>
11873 });
11874 </code></pre>
11875      * The only required property is url. The optional properties nocache, text and scripts
11876      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11877      * @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}
11878      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11879      * @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.
11880      */
11881     update : function(url, params, callback, discardUrl){
11882         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11883             var method = this.method,
11884                 cfg;
11885             if(typeof url == "object"){ // must be config object
11886                 cfg = url;
11887                 url = cfg.url;
11888                 params = params || cfg.params;
11889                 callback = callback || cfg.callback;
11890                 discardUrl = discardUrl || cfg.discardUrl;
11891                 if(callback && cfg.scope){
11892                     callback = callback.createDelegate(cfg.scope);
11893                 }
11894                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11895                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11896                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11897                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11898                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11899             }
11900             this.showLoading();
11901             if(!discardUrl){
11902                 this.defaultUrl = url;
11903             }
11904             if(typeof url == "function"){
11905                 url = url.call(this);
11906             }
11907
11908             method = method || (params ? "POST" : "GET");
11909             if(method == "GET"){
11910                 url = this.prepareUrl(url);
11911             }
11912
11913             var o = Roo.apply(cfg ||{}, {
11914                 url : url,
11915                 params: params,
11916                 success: this.successDelegate,
11917                 failure: this.failureDelegate,
11918                 callback: undefined,
11919                 timeout: (this.timeout*1000),
11920                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11921             });
11922             Roo.log("updated manager called with timeout of " + o.timeout);
11923             this.transaction = Roo.Ajax.request(o);
11924         }
11925     },
11926
11927     /**
11928      * 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.
11929      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11930      * @param {String/HTMLElement} form The form Id or form element
11931      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11932      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11933      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11934      */
11935     formUpdate : function(form, url, reset, callback){
11936         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11937             if(typeof url == "function"){
11938                 url = url.call(this);
11939             }
11940             form = Roo.getDom(form);
11941             this.transaction = Roo.Ajax.request({
11942                 form: form,
11943                 url:url,
11944                 success: this.successDelegate,
11945                 failure: this.failureDelegate,
11946                 timeout: (this.timeout*1000),
11947                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11948             });
11949             this.showLoading.defer(1, this);
11950         }
11951     },
11952
11953     /**
11954      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11955      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11956      */
11957     refresh : function(callback){
11958         if(this.defaultUrl == null){
11959             return;
11960         }
11961         this.update(this.defaultUrl, null, callback, true);
11962     },
11963
11964     /**
11965      * Set this element to auto refresh.
11966      * @param {Number} interval How often to update (in seconds).
11967      * @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)
11968      * @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}
11969      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11970      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11971      */
11972     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11973         if(refreshNow){
11974             this.update(url || this.defaultUrl, params, callback, true);
11975         }
11976         if(this.autoRefreshProcId){
11977             clearInterval(this.autoRefreshProcId);
11978         }
11979         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11980     },
11981
11982     /**
11983      * Stop auto refresh on this element.
11984      */
11985      stopAutoRefresh : function(){
11986         if(this.autoRefreshProcId){
11987             clearInterval(this.autoRefreshProcId);
11988             delete this.autoRefreshProcId;
11989         }
11990     },
11991
11992     isAutoRefreshing : function(){
11993        return this.autoRefreshProcId ? true : false;
11994     },
11995     /**
11996      * Called to update the element to "Loading" state. Override to perform custom action.
11997      */
11998     showLoading : function(){
11999         if(this.showLoadIndicator){
12000             this.el.update(this.indicatorText);
12001         }
12002     },
12003
12004     /**
12005      * Adds unique parameter to query string if disableCaching = true
12006      * @private
12007      */
12008     prepareUrl : function(url){
12009         if(this.disableCaching){
12010             var append = "_dc=" + (new Date().getTime());
12011             if(url.indexOf("?") !== -1){
12012                 url += "&" + append;
12013             }else{
12014                 url += "?" + append;
12015             }
12016         }
12017         return url;
12018     },
12019
12020     /**
12021      * @private
12022      */
12023     processSuccess : function(response){
12024         this.transaction = null;
12025         if(response.argument.form && response.argument.reset){
12026             try{ // put in try/catch since some older FF releases had problems with this
12027                 response.argument.form.reset();
12028             }catch(e){}
12029         }
12030         if(this.loadScripts){
12031             this.renderer.render(this.el, response, this,
12032                 this.updateComplete.createDelegate(this, [response]));
12033         }else{
12034             this.renderer.render(this.el, response, this);
12035             this.updateComplete(response);
12036         }
12037     },
12038
12039     updateComplete : function(response){
12040         this.fireEvent("update", this.el, response);
12041         if(typeof response.argument.callback == "function"){
12042             response.argument.callback(this.el, true, response);
12043         }
12044     },
12045
12046     /**
12047      * @private
12048      */
12049     processFailure : function(response){
12050         this.transaction = null;
12051         this.fireEvent("failure", this.el, response);
12052         if(typeof response.argument.callback == "function"){
12053             response.argument.callback(this.el, false, response);
12054         }
12055     },
12056
12057     /**
12058      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12059      * @param {Object} renderer The object implementing the render() method
12060      */
12061     setRenderer : function(renderer){
12062         this.renderer = renderer;
12063     },
12064
12065     getRenderer : function(){
12066        return this.renderer;
12067     },
12068
12069     /**
12070      * Set the defaultUrl used for updates
12071      * @param {String/Function} defaultUrl The url or a function to call to get the url
12072      */
12073     setDefaultUrl : function(defaultUrl){
12074         this.defaultUrl = defaultUrl;
12075     },
12076
12077     /**
12078      * Aborts the executing transaction
12079      */
12080     abort : function(){
12081         if(this.transaction){
12082             Roo.Ajax.abort(this.transaction);
12083         }
12084     },
12085
12086     /**
12087      * Returns true if an update is in progress
12088      * @return {Boolean}
12089      */
12090     isUpdating : function(){
12091         if(this.transaction){
12092             return Roo.Ajax.isLoading(this.transaction);
12093         }
12094         return false;
12095     }
12096 });
12097
12098 /**
12099  * @class Roo.UpdateManager.defaults
12100  * @static (not really - but it helps the doc tool)
12101  * The defaults collection enables customizing the default properties of UpdateManager
12102  */
12103    Roo.UpdateManager.defaults = {
12104        /**
12105          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12106          * @type Number
12107          */
12108          timeout : 30,
12109
12110          /**
12111          * True to process scripts by default (Defaults to false).
12112          * @type Boolean
12113          */
12114         loadScripts : false,
12115
12116         /**
12117         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12118         * @type String
12119         */
12120         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12121         /**
12122          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12123          * @type Boolean
12124          */
12125         disableCaching : false,
12126         /**
12127          * Whether to show indicatorText when loading (Defaults to true).
12128          * @type Boolean
12129          */
12130         showLoadIndicator : true,
12131         /**
12132          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12133          * @type String
12134          */
12135         indicatorText : '<div class="loading-indicator">Loading...</div>'
12136    };
12137
12138 /**
12139  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12140  *Usage:
12141  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12142  * @param {String/HTMLElement/Roo.Element} el The element to update
12143  * @param {String} url The url
12144  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12145  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12146  * @static
12147  * @deprecated
12148  * @member Roo.UpdateManager
12149  */
12150 Roo.UpdateManager.updateElement = function(el, url, params, options){
12151     var um = Roo.get(el, true).getUpdateManager();
12152     Roo.apply(um, options);
12153     um.update(url, params, options ? options.callback : null);
12154 };
12155 // alias for backwards compat
12156 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12157 /**
12158  * @class Roo.UpdateManager.BasicRenderer
12159  * Default Content renderer. Updates the elements innerHTML with the responseText.
12160  */
12161 Roo.UpdateManager.BasicRenderer = function(){};
12162
12163 Roo.UpdateManager.BasicRenderer.prototype = {
12164     /**
12165      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12166      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12167      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12168      * @param {Roo.Element} el The element being rendered
12169      * @param {Object} response The YUI Connect response object
12170      * @param {UpdateManager} updateManager The calling update manager
12171      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12172      */
12173      render : function(el, response, updateManager, callback){
12174         el.update(response.responseText, updateManager.loadScripts, callback);
12175     }
12176 };
12177 /*
12178  * Based on:
12179  * Roo JS
12180  * (c)) Alan Knowles
12181  * Licence : LGPL
12182  */
12183
12184
12185 /**
12186  * @class Roo.DomTemplate
12187  * @extends Roo.Template
12188  * An effort at a dom based template engine..
12189  *
12190  * Similar to XTemplate, except it uses dom parsing to create the template..
12191  *
12192  * Supported features:
12193  *
12194  *  Tags:
12195
12196 <pre><code>
12197       {a_variable} - output encoded.
12198       {a_variable.format:("Y-m-d")} - call a method on the variable
12199       {a_variable:raw} - unencoded output
12200       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12201       {a_variable:this.method_on_template(...)} - call a method on the template object.
12202  
12203 </code></pre>
12204  *  The tpl tag:
12205 <pre><code>
12206         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12207         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12208         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12209         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12210   
12211 </code></pre>
12212  *      
12213  */
12214 Roo.DomTemplate = function()
12215 {
12216      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12217      if (this.html) {
12218         this.compile();
12219      }
12220 };
12221
12222
12223 Roo.extend(Roo.DomTemplate, Roo.Template, {
12224     /**
12225      * id counter for sub templates.
12226      */
12227     id : 0,
12228     /**
12229      * flag to indicate if dom parser is inside a pre,
12230      * it will strip whitespace if not.
12231      */
12232     inPre : false,
12233     
12234     /**
12235      * The various sub templates
12236      */
12237     tpls : false,
12238     
12239     
12240     
12241     /**
12242      *
12243      * basic tag replacing syntax
12244      * WORD:WORD()
12245      *
12246      * // you can fake an object call by doing this
12247      *  x.t:(test,tesT) 
12248      * 
12249      */
12250     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12251     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12252     
12253     iterChild : function (node, method) {
12254         
12255         var oldPre = this.inPre;
12256         if (node.tagName == 'PRE') {
12257             this.inPre = true;
12258         }
12259         for( var i = 0; i < node.childNodes.length; i++) {
12260             method.call(this, node.childNodes[i]);
12261         }
12262         this.inPre = oldPre;
12263     },
12264     
12265     
12266     
12267     /**
12268      * compile the template
12269      *
12270      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12271      *
12272      */
12273     compile: function()
12274     {
12275         var s = this.html;
12276         
12277         // covert the html into DOM...
12278         var doc = false;
12279         var div =false;
12280         try {
12281             doc = document.implementation.createHTMLDocument("");
12282             doc.documentElement.innerHTML =   this.html  ;
12283             div = doc.documentElement;
12284         } catch (e) {
12285             // old IE... - nasty -- it causes all sorts of issues.. with
12286             // images getting pulled from server..
12287             div = document.createElement('div');
12288             div.innerHTML = this.html;
12289         }
12290         //doc.documentElement.innerHTML = htmlBody
12291          
12292         
12293         
12294         this.tpls = [];
12295         var _t = this;
12296         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12297         
12298         var tpls = this.tpls;
12299         
12300         // create a top level template from the snippet..
12301         
12302         //Roo.log(div.innerHTML);
12303         
12304         var tpl = {
12305             uid : 'master',
12306             id : this.id++,
12307             attr : false,
12308             value : false,
12309             body : div.innerHTML,
12310             
12311             forCall : false,
12312             execCall : false,
12313             dom : div,
12314             isTop : true
12315             
12316         };
12317         tpls.unshift(tpl);
12318         
12319         
12320         // compile them...
12321         this.tpls = [];
12322         Roo.each(tpls, function(tp){
12323             this.compileTpl(tp);
12324             this.tpls[tp.id] = tp;
12325         }, this);
12326         
12327         this.master = tpls[0];
12328         return this;
12329         
12330         
12331     },
12332     
12333     compileNode : function(node, istop) {
12334         // test for
12335         //Roo.log(node);
12336         
12337         
12338         // skip anything not a tag..
12339         if (node.nodeType != 1) {
12340             if (node.nodeType == 3 && !this.inPre) {
12341                 // reduce white space..
12342                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12343                 
12344             }
12345             return;
12346         }
12347         
12348         var tpl = {
12349             uid : false,
12350             id : false,
12351             attr : false,
12352             value : false,
12353             body : '',
12354             
12355             forCall : false,
12356             execCall : false,
12357             dom : false,
12358             isTop : istop
12359             
12360             
12361         };
12362         
12363         
12364         switch(true) {
12365             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12366             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12367             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12368             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12369             // no default..
12370         }
12371         
12372         
12373         if (!tpl.attr) {
12374             // just itterate children..
12375             this.iterChild(node,this.compileNode);
12376             return;
12377         }
12378         tpl.uid = this.id++;
12379         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12380         node.removeAttribute('roo-'+ tpl.attr);
12381         if (tpl.attr != 'name') {
12382             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12383             node.parentNode.replaceChild(placeholder,  node);
12384         } else {
12385             
12386             var placeholder =  document.createElement('span');
12387             placeholder.className = 'roo-tpl-' + tpl.value;
12388             node.parentNode.replaceChild(placeholder,  node);
12389         }
12390         
12391         // parent now sees '{domtplXXXX}
12392         this.iterChild(node,this.compileNode);
12393         
12394         // we should now have node body...
12395         var div = document.createElement('div');
12396         div.appendChild(node);
12397         tpl.dom = node;
12398         // this has the unfortunate side effect of converting tagged attributes
12399         // eg. href="{...}" into %7C...%7D
12400         // this has been fixed by searching for those combo's although it's a bit hacky..
12401         
12402         
12403         tpl.body = div.innerHTML;
12404         
12405         
12406          
12407         tpl.id = tpl.uid;
12408         switch(tpl.attr) {
12409             case 'for' :
12410                 switch (tpl.value) {
12411                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12412                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12413                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12414                 }
12415                 break;
12416             
12417             case 'exec':
12418                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12419                 break;
12420             
12421             case 'if':     
12422                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12423                 break;
12424             
12425             case 'name':
12426                 tpl.id  = tpl.value; // replace non characters???
12427                 break;
12428             
12429         }
12430         
12431         
12432         this.tpls.push(tpl);
12433         
12434         
12435         
12436     },
12437     
12438     
12439     
12440     
12441     /**
12442      * Compile a segment of the template into a 'sub-template'
12443      *
12444      * 
12445      * 
12446      *
12447      */
12448     compileTpl : function(tpl)
12449     {
12450         var fm = Roo.util.Format;
12451         var useF = this.disableFormats !== true;
12452         
12453         var sep = Roo.isGecko ? "+\n" : ",\n";
12454         
12455         var undef = function(str) {
12456             Roo.debug && Roo.log("Property not found :"  + str);
12457             return '';
12458         };
12459           
12460         //Roo.log(tpl.body);
12461         
12462         
12463         
12464         var fn = function(m, lbrace, name, format, args)
12465         {
12466             //Roo.log("ARGS");
12467             //Roo.log(arguments);
12468             args = args ? args.replace(/\\'/g,"'") : args;
12469             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12470             if (typeof(format) == 'undefined') {
12471                 format =  'htmlEncode'; 
12472             }
12473             if (format == 'raw' ) {
12474                 format = false;
12475             }
12476             
12477             if(name.substr(0, 6) == 'domtpl'){
12478                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12479             }
12480             
12481             // build an array of options to determine if value is undefined..
12482             
12483             // basically get 'xxxx.yyyy' then do
12484             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12485             //    (function () { Roo.log("Property not found"); return ''; })() :
12486             //    ......
12487             
12488             var udef_ar = [];
12489             var lookfor = '';
12490             Roo.each(name.split('.'), function(st) {
12491                 lookfor += (lookfor.length ? '.': '') + st;
12492                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12493             });
12494             
12495             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12496             
12497             
12498             if(format && useF){
12499                 
12500                 args = args ? ',' + args : "";
12501                  
12502                 if(format.substr(0, 5) != "this."){
12503                     format = "fm." + format + '(';
12504                 }else{
12505                     format = 'this.call("'+ format.substr(5) + '", ';
12506                     args = ", values";
12507                 }
12508                 
12509                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12510             }
12511              
12512             if (args && args.length) {
12513                 // called with xxyx.yuu:(test,test)
12514                 // change to ()
12515                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12516             }
12517             // raw.. - :raw modifier..
12518             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12519             
12520         };
12521         var body;
12522         // branched to use + in gecko and [].join() in others
12523         if(Roo.isGecko){
12524             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12525                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12526                     "';};};";
12527         }else{
12528             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12529             body.push(tpl.body.replace(/(\r\n|\n)/g,
12530                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12531             body.push("'].join('');};};");
12532             body = body.join('');
12533         }
12534         
12535         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12536        
12537         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12538         eval(body);
12539         
12540         return this;
12541     },
12542      
12543     /**
12544      * same as applyTemplate, except it's done to one of the subTemplates
12545      * when using named templates, you can do:
12546      *
12547      * var str = pl.applySubTemplate('your-name', values);
12548      *
12549      * 
12550      * @param {Number} id of the template
12551      * @param {Object} values to apply to template
12552      * @param {Object} parent (normaly the instance of this object)
12553      */
12554     applySubTemplate : function(id, values, parent)
12555     {
12556         
12557         
12558         var t = this.tpls[id];
12559         
12560         
12561         try { 
12562             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12563                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12564                 return '';
12565             }
12566         } catch(e) {
12567             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12568             Roo.log(values);
12569           
12570             return '';
12571         }
12572         try { 
12573             
12574             if(t.execCall && t.execCall.call(this, values, parent)){
12575                 return '';
12576             }
12577         } catch(e) {
12578             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12579             Roo.log(values);
12580             return '';
12581         }
12582         
12583         try {
12584             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12585             parent = t.target ? values : parent;
12586             if(t.forCall && vs instanceof Array){
12587                 var buf = [];
12588                 for(var i = 0, len = vs.length; i < len; i++){
12589                     try {
12590                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12591                     } catch (e) {
12592                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12593                         Roo.log(e.body);
12594                         //Roo.log(t.compiled);
12595                         Roo.log(vs[i]);
12596                     }   
12597                 }
12598                 return buf.join('');
12599             }
12600         } catch (e) {
12601             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12602             Roo.log(values);
12603             return '';
12604         }
12605         try {
12606             return t.compiled.call(this, vs, parent);
12607         } catch (e) {
12608             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12609             Roo.log(e.body);
12610             //Roo.log(t.compiled);
12611             Roo.log(values);
12612             return '';
12613         }
12614     },
12615
12616    
12617
12618     applyTemplate : function(values){
12619         return this.master.compiled.call(this, values, {});
12620         //var s = this.subs;
12621     },
12622
12623     apply : function(){
12624         return this.applyTemplate.apply(this, arguments);
12625     }
12626
12627  });
12628
12629 Roo.DomTemplate.from = function(el){
12630     el = Roo.getDom(el);
12631     return new Roo.Domtemplate(el.value || el.innerHTML);
12632 };/*
12633  * Based on:
12634  * Ext JS Library 1.1.1
12635  * Copyright(c) 2006-2007, Ext JS, LLC.
12636  *
12637  * Originally Released Under LGPL - original licence link has changed is not relivant.
12638  *
12639  * Fork - LGPL
12640  * <script type="text/javascript">
12641  */
12642
12643 /**
12644  * @class Roo.util.DelayedTask
12645  * Provides a convenient method of performing setTimeout where a new
12646  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12647  * You can use this class to buffer
12648  * the keypress events for a certain number of milliseconds, and perform only if they stop
12649  * for that amount of time.
12650  * @constructor The parameters to this constructor serve as defaults and are not required.
12651  * @param {Function} fn (optional) The default function to timeout
12652  * @param {Object} scope (optional) The default scope of that timeout
12653  * @param {Array} args (optional) The default Array of arguments
12654  */
12655 Roo.util.DelayedTask = function(fn, scope, args){
12656     var id = null, d, t;
12657
12658     var call = function(){
12659         var now = new Date().getTime();
12660         if(now - t >= d){
12661             clearInterval(id);
12662             id = null;
12663             fn.apply(scope, args || []);
12664         }
12665     };
12666     /**
12667      * Cancels any pending timeout and queues a new one
12668      * @param {Number} delay The milliseconds to delay
12669      * @param {Function} newFn (optional) Overrides function passed to constructor
12670      * @param {Object} newScope (optional) Overrides scope passed to constructor
12671      * @param {Array} newArgs (optional) Overrides args passed to constructor
12672      */
12673     this.delay = function(delay, newFn, newScope, newArgs){
12674         if(id && delay != d){
12675             this.cancel();
12676         }
12677         d = delay;
12678         t = new Date().getTime();
12679         fn = newFn || fn;
12680         scope = newScope || scope;
12681         args = newArgs || args;
12682         if(!id){
12683             id = setInterval(call, d);
12684         }
12685     };
12686
12687     /**
12688      * Cancel the last queued timeout
12689      */
12690     this.cancel = function(){
12691         if(id){
12692             clearInterval(id);
12693             id = null;
12694         }
12695     };
12696 };/*
12697  * Based on:
12698  * Ext JS Library 1.1.1
12699  * Copyright(c) 2006-2007, Ext JS, LLC.
12700  *
12701  * Originally Released Under LGPL - original licence link has changed is not relivant.
12702  *
12703  * Fork - LGPL
12704  * <script type="text/javascript">
12705  */
12706  
12707  
12708 Roo.util.TaskRunner = function(interval){
12709     interval = interval || 10;
12710     var tasks = [], removeQueue = [];
12711     var id = 0;
12712     var running = false;
12713
12714     var stopThread = function(){
12715         running = false;
12716         clearInterval(id);
12717         id = 0;
12718     };
12719
12720     var startThread = function(){
12721         if(!running){
12722             running = true;
12723             id = setInterval(runTasks, interval);
12724         }
12725     };
12726
12727     var removeTask = function(task){
12728         removeQueue.push(task);
12729         if(task.onStop){
12730             task.onStop();
12731         }
12732     };
12733
12734     var runTasks = function(){
12735         if(removeQueue.length > 0){
12736             for(var i = 0, len = removeQueue.length; i < len; i++){
12737                 tasks.remove(removeQueue[i]);
12738             }
12739             removeQueue = [];
12740             if(tasks.length < 1){
12741                 stopThread();
12742                 return;
12743             }
12744         }
12745         var now = new Date().getTime();
12746         for(var i = 0, len = tasks.length; i < len; ++i){
12747             var t = tasks[i];
12748             var itime = now - t.taskRunTime;
12749             if(t.interval <= itime){
12750                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12751                 t.taskRunTime = now;
12752                 if(rt === false || t.taskRunCount === t.repeat){
12753                     removeTask(t);
12754                     return;
12755                 }
12756             }
12757             if(t.duration && t.duration <= (now - t.taskStartTime)){
12758                 removeTask(t);
12759             }
12760         }
12761     };
12762
12763     /**
12764      * Queues a new task.
12765      * @param {Object} task
12766      */
12767     this.start = function(task){
12768         tasks.push(task);
12769         task.taskStartTime = new Date().getTime();
12770         task.taskRunTime = 0;
12771         task.taskRunCount = 0;
12772         startThread();
12773         return task;
12774     };
12775
12776     this.stop = function(task){
12777         removeTask(task);
12778         return task;
12779     };
12780
12781     this.stopAll = function(){
12782         stopThread();
12783         for(var i = 0, len = tasks.length; i < len; i++){
12784             if(tasks[i].onStop){
12785                 tasks[i].onStop();
12786             }
12787         }
12788         tasks = [];
12789         removeQueue = [];
12790     };
12791 };
12792
12793 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12794  * Based on:
12795  * Ext JS Library 1.1.1
12796  * Copyright(c) 2006-2007, Ext JS, LLC.
12797  *
12798  * Originally Released Under LGPL - original licence link has changed is not relivant.
12799  *
12800  * Fork - LGPL
12801  * <script type="text/javascript">
12802  */
12803
12804  
12805 /**
12806  * @class Roo.util.MixedCollection
12807  * @extends Roo.util.Observable
12808  * A Collection class that maintains both numeric indexes and keys and exposes events.
12809  * @constructor
12810  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12811  * collection (defaults to false)
12812  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12813  * and return the key value for that item.  This is used when available to look up the key on items that
12814  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12815  * equivalent to providing an implementation for the {@link #getKey} method.
12816  */
12817 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12818     this.items = [];
12819     this.map = {};
12820     this.keys = [];
12821     this.length = 0;
12822     this.addEvents({
12823         /**
12824          * @event clear
12825          * Fires when the collection is cleared.
12826          */
12827         "clear" : true,
12828         /**
12829          * @event add
12830          * Fires when an item is added to the collection.
12831          * @param {Number} index The index at which the item was added.
12832          * @param {Object} o The item added.
12833          * @param {String} key The key associated with the added item.
12834          */
12835         "add" : true,
12836         /**
12837          * @event replace
12838          * Fires when an item is replaced in the collection.
12839          * @param {String} key he key associated with the new added.
12840          * @param {Object} old The item being replaced.
12841          * @param {Object} new The new item.
12842          */
12843         "replace" : true,
12844         /**
12845          * @event remove
12846          * Fires when an item is removed from the collection.
12847          * @param {Object} o The item being removed.
12848          * @param {String} key (optional) The key associated with the removed item.
12849          */
12850         "remove" : true,
12851         "sort" : true
12852     });
12853     this.allowFunctions = allowFunctions === true;
12854     if(keyFn){
12855         this.getKey = keyFn;
12856     }
12857     Roo.util.MixedCollection.superclass.constructor.call(this);
12858 };
12859
12860 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12861     allowFunctions : false,
12862     
12863 /**
12864  * Adds an item to the collection.
12865  * @param {String} key The key to associate with the item
12866  * @param {Object} o The item to add.
12867  * @return {Object} The item added.
12868  */
12869     add : function(key, o){
12870         if(arguments.length == 1){
12871             o = arguments[0];
12872             key = this.getKey(o);
12873         }
12874         if(typeof key == "undefined" || key === null){
12875             this.length++;
12876             this.items.push(o);
12877             this.keys.push(null);
12878         }else{
12879             var old = this.map[key];
12880             if(old){
12881                 return this.replace(key, o);
12882             }
12883             this.length++;
12884             this.items.push(o);
12885             this.map[key] = o;
12886             this.keys.push(key);
12887         }
12888         this.fireEvent("add", this.length-1, o, key);
12889         return o;
12890     },
12891        
12892 /**
12893   * MixedCollection has a generic way to fetch keys if you implement getKey.
12894 <pre><code>
12895 // normal way
12896 var mc = new Roo.util.MixedCollection();
12897 mc.add(someEl.dom.id, someEl);
12898 mc.add(otherEl.dom.id, otherEl);
12899 //and so on
12900
12901 // using getKey
12902 var mc = new Roo.util.MixedCollection();
12903 mc.getKey = function(el){
12904    return el.dom.id;
12905 };
12906 mc.add(someEl);
12907 mc.add(otherEl);
12908
12909 // or via the constructor
12910 var mc = new Roo.util.MixedCollection(false, function(el){
12911    return el.dom.id;
12912 });
12913 mc.add(someEl);
12914 mc.add(otherEl);
12915 </code></pre>
12916  * @param o {Object} The item for which to find the key.
12917  * @return {Object} The key for the passed item.
12918  */
12919     getKey : function(o){
12920          return o.id; 
12921     },
12922    
12923 /**
12924  * Replaces an item in the collection.
12925  * @param {String} key The key associated with the item to replace, or the item to replace.
12926  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12927  * @return {Object}  The new item.
12928  */
12929     replace : function(key, o){
12930         if(arguments.length == 1){
12931             o = arguments[0];
12932             key = this.getKey(o);
12933         }
12934         var old = this.item(key);
12935         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12936              return this.add(key, o);
12937         }
12938         var index = this.indexOfKey(key);
12939         this.items[index] = o;
12940         this.map[key] = o;
12941         this.fireEvent("replace", key, old, o);
12942         return o;
12943     },
12944    
12945 /**
12946  * Adds all elements of an Array or an Object to the collection.
12947  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12948  * an Array of values, each of which are added to the collection.
12949  */
12950     addAll : function(objs){
12951         if(arguments.length > 1 || objs instanceof Array){
12952             var args = arguments.length > 1 ? arguments : objs;
12953             for(var i = 0, len = args.length; i < len; i++){
12954                 this.add(args[i]);
12955             }
12956         }else{
12957             for(var key in objs){
12958                 if(this.allowFunctions || typeof objs[key] != "function"){
12959                     this.add(key, objs[key]);
12960                 }
12961             }
12962         }
12963     },
12964    
12965 /**
12966  * Executes the specified function once for every item in the collection, passing each
12967  * item as the first and only parameter. returning false from the function will stop the iteration.
12968  * @param {Function} fn The function to execute for each item.
12969  * @param {Object} scope (optional) The scope in which to execute the function.
12970  */
12971     each : function(fn, scope){
12972         var items = [].concat(this.items); // each safe for removal
12973         for(var i = 0, len = items.length; i < len; i++){
12974             if(fn.call(scope || items[i], items[i], i, len) === false){
12975                 break;
12976             }
12977         }
12978     },
12979    
12980 /**
12981  * Executes the specified function once for every key in the collection, passing each
12982  * key, and its associated item as the first two parameters.
12983  * @param {Function} fn The function to execute for each item.
12984  * @param {Object} scope (optional) The scope in which to execute the function.
12985  */
12986     eachKey : function(fn, scope){
12987         for(var i = 0, len = this.keys.length; i < len; i++){
12988             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12989         }
12990     },
12991    
12992 /**
12993  * Returns the first item in the collection which elicits a true return value from the
12994  * passed selection function.
12995  * @param {Function} fn The selection function to execute for each item.
12996  * @param {Object} scope (optional) The scope in which to execute the function.
12997  * @return {Object} The first item in the collection which returned true from the selection function.
12998  */
12999     find : function(fn, scope){
13000         for(var i = 0, len = this.items.length; i < len; i++){
13001             if(fn.call(scope || window, this.items[i], this.keys[i])){
13002                 return this.items[i];
13003             }
13004         }
13005         return null;
13006     },
13007    
13008 /**
13009  * Inserts an item at the specified index in the collection.
13010  * @param {Number} index The index to insert the item at.
13011  * @param {String} key The key to associate with the new item, or the item itself.
13012  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13013  * @return {Object} The item inserted.
13014  */
13015     insert : function(index, key, o){
13016         if(arguments.length == 2){
13017             o = arguments[1];
13018             key = this.getKey(o);
13019         }
13020         if(index >= this.length){
13021             return this.add(key, o);
13022         }
13023         this.length++;
13024         this.items.splice(index, 0, o);
13025         if(typeof key != "undefined" && key != null){
13026             this.map[key] = o;
13027         }
13028         this.keys.splice(index, 0, key);
13029         this.fireEvent("add", index, o, key);
13030         return o;
13031     },
13032    
13033 /**
13034  * Removed an item from the collection.
13035  * @param {Object} o The item to remove.
13036  * @return {Object} The item removed.
13037  */
13038     remove : function(o){
13039         return this.removeAt(this.indexOf(o));
13040     },
13041    
13042 /**
13043  * Remove an item from a specified index in the collection.
13044  * @param {Number} index The index within the collection of the item to remove.
13045  */
13046     removeAt : function(index){
13047         if(index < this.length && index >= 0){
13048             this.length--;
13049             var o = this.items[index];
13050             this.items.splice(index, 1);
13051             var key = this.keys[index];
13052             if(typeof key != "undefined"){
13053                 delete this.map[key];
13054             }
13055             this.keys.splice(index, 1);
13056             this.fireEvent("remove", o, key);
13057         }
13058     },
13059    
13060 /**
13061  * Removed an item associated with the passed key fom the collection.
13062  * @param {String} key The key of the item to remove.
13063  */
13064     removeKey : function(key){
13065         return this.removeAt(this.indexOfKey(key));
13066     },
13067    
13068 /**
13069  * Returns the number of items in the collection.
13070  * @return {Number} the number of items in the collection.
13071  */
13072     getCount : function(){
13073         return this.length; 
13074     },
13075    
13076 /**
13077  * Returns index within the collection of the passed Object.
13078  * @param {Object} o The item to find the index of.
13079  * @return {Number} index of the item.
13080  */
13081     indexOf : function(o){
13082         if(!this.items.indexOf){
13083             for(var i = 0, len = this.items.length; i < len; i++){
13084                 if(this.items[i] == o) return i;
13085             }
13086             return -1;
13087         }else{
13088             return this.items.indexOf(o);
13089         }
13090     },
13091    
13092 /**
13093  * Returns index within the collection of the passed key.
13094  * @param {String} key The key to find the index of.
13095  * @return {Number} index of the key.
13096  */
13097     indexOfKey : function(key){
13098         if(!this.keys.indexOf){
13099             for(var i = 0, len = this.keys.length; i < len; i++){
13100                 if(this.keys[i] == key) return i;
13101             }
13102             return -1;
13103         }else{
13104             return this.keys.indexOf(key);
13105         }
13106     },
13107    
13108 /**
13109  * Returns the item associated with the passed key OR index. Key has priority over index.
13110  * @param {String/Number} key The key or index of the item.
13111  * @return {Object} The item associated with the passed key.
13112  */
13113     item : function(key){
13114         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13115         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13116     },
13117     
13118 /**
13119  * Returns the item at the specified index.
13120  * @param {Number} index The index of the item.
13121  * @return {Object}
13122  */
13123     itemAt : function(index){
13124         return this.items[index];
13125     },
13126     
13127 /**
13128  * Returns the item associated with the passed key.
13129  * @param {String/Number} key The key of the item.
13130  * @return {Object} The item associated with the passed key.
13131  */
13132     key : function(key){
13133         return this.map[key];
13134     },
13135    
13136 /**
13137  * Returns true if the collection contains the passed Object as an item.
13138  * @param {Object} o  The Object to look for in the collection.
13139  * @return {Boolean} True if the collection contains the Object as an item.
13140  */
13141     contains : function(o){
13142         return this.indexOf(o) != -1;
13143     },
13144    
13145 /**
13146  * Returns true if the collection contains the passed Object as a key.
13147  * @param {String} key The key to look for in the collection.
13148  * @return {Boolean} True if the collection contains the Object as a key.
13149  */
13150     containsKey : function(key){
13151         return typeof this.map[key] != "undefined";
13152     },
13153    
13154 /**
13155  * Removes all items from the collection.
13156  */
13157     clear : function(){
13158         this.length = 0;
13159         this.items = [];
13160         this.keys = [];
13161         this.map = {};
13162         this.fireEvent("clear");
13163     },
13164    
13165 /**
13166  * Returns the first item in the collection.
13167  * @return {Object} the first item in the collection..
13168  */
13169     first : function(){
13170         return this.items[0]; 
13171     },
13172    
13173 /**
13174  * Returns the last item in the collection.
13175  * @return {Object} the last item in the collection..
13176  */
13177     last : function(){
13178         return this.items[this.length-1];   
13179     },
13180     
13181     _sort : function(property, dir, fn){
13182         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13183         fn = fn || function(a, b){
13184             return a-b;
13185         };
13186         var c = [], k = this.keys, items = this.items;
13187         for(var i = 0, len = items.length; i < len; i++){
13188             c[c.length] = {key: k[i], value: items[i], index: i};
13189         }
13190         c.sort(function(a, b){
13191             var v = fn(a[property], b[property]) * dsc;
13192             if(v == 0){
13193                 v = (a.index < b.index ? -1 : 1);
13194             }
13195             return v;
13196         });
13197         for(var i = 0, len = c.length; i < len; i++){
13198             items[i] = c[i].value;
13199             k[i] = c[i].key;
13200         }
13201         this.fireEvent("sort", this);
13202     },
13203     
13204     /**
13205      * Sorts this collection with the passed comparison function
13206      * @param {String} direction (optional) "ASC" or "DESC"
13207      * @param {Function} fn (optional) comparison function
13208      */
13209     sort : function(dir, fn){
13210         this._sort("value", dir, fn);
13211     },
13212     
13213     /**
13214      * Sorts this collection by keys
13215      * @param {String} direction (optional) "ASC" or "DESC"
13216      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13217      */
13218     keySort : function(dir, fn){
13219         this._sort("key", dir, fn || function(a, b){
13220             return String(a).toUpperCase()-String(b).toUpperCase();
13221         });
13222     },
13223     
13224     /**
13225      * Returns a range of items in this collection
13226      * @param {Number} startIndex (optional) defaults to 0
13227      * @param {Number} endIndex (optional) default to the last item
13228      * @return {Array} An array of items
13229      */
13230     getRange : function(start, end){
13231         var items = this.items;
13232         if(items.length < 1){
13233             return [];
13234         }
13235         start = start || 0;
13236         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13237         var r = [];
13238         if(start <= end){
13239             for(var i = start; i <= end; i++) {
13240                     r[r.length] = items[i];
13241             }
13242         }else{
13243             for(var i = start; i >= end; i--) {
13244                     r[r.length] = items[i];
13245             }
13246         }
13247         return r;
13248     },
13249         
13250     /**
13251      * Filter the <i>objects</i> in this collection by a specific property. 
13252      * Returns a new collection that has been filtered.
13253      * @param {String} property A property on your objects
13254      * @param {String/RegExp} value Either string that the property values 
13255      * should start with or a RegExp to test against the property
13256      * @return {MixedCollection} The new filtered collection
13257      */
13258     filter : function(property, value){
13259         if(!value.exec){ // not a regex
13260             value = String(value);
13261             if(value.length == 0){
13262                 return this.clone();
13263             }
13264             value = new RegExp("^" + Roo.escapeRe(value), "i");
13265         }
13266         return this.filterBy(function(o){
13267             return o && value.test(o[property]);
13268         });
13269         },
13270     
13271     /**
13272      * Filter by a function. * Returns a new collection that has been filtered.
13273      * The passed function will be called with each 
13274      * object in the collection. If the function returns true, the value is included 
13275      * otherwise it is filtered.
13276      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13277      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13278      * @return {MixedCollection} The new filtered collection
13279      */
13280     filterBy : function(fn, scope){
13281         var r = new Roo.util.MixedCollection();
13282         r.getKey = this.getKey;
13283         var k = this.keys, it = this.items;
13284         for(var i = 0, len = it.length; i < len; i++){
13285             if(fn.call(scope||this, it[i], k[i])){
13286                                 r.add(k[i], it[i]);
13287                         }
13288         }
13289         return r;
13290     },
13291     
13292     /**
13293      * Creates a duplicate of this collection
13294      * @return {MixedCollection}
13295      */
13296     clone : function(){
13297         var r = new Roo.util.MixedCollection();
13298         var k = this.keys, it = this.items;
13299         for(var i = 0, len = it.length; i < len; i++){
13300             r.add(k[i], it[i]);
13301         }
13302         r.getKey = this.getKey;
13303         return r;
13304     }
13305 });
13306 /**
13307  * Returns the item associated with the passed key or index.
13308  * @method
13309  * @param {String/Number} key The key or index of the item.
13310  * @return {Object} The item associated with the passed key.
13311  */
13312 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13313  * Based on:
13314  * Ext JS Library 1.1.1
13315  * Copyright(c) 2006-2007, Ext JS, LLC.
13316  *
13317  * Originally Released Under LGPL - original licence link has changed is not relivant.
13318  *
13319  * Fork - LGPL
13320  * <script type="text/javascript">
13321  */
13322 /**
13323  * @class Roo.util.JSON
13324  * Modified version of Douglas Crockford"s json.js that doesn"t
13325  * mess with the Object prototype 
13326  * http://www.json.org/js.html
13327  * @singleton
13328  */
13329 Roo.util.JSON = new (function(){
13330     var useHasOwn = {}.hasOwnProperty ? true : false;
13331     
13332     // crashes Safari in some instances
13333     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13334     
13335     var pad = function(n) {
13336         return n < 10 ? "0" + n : n;
13337     };
13338     
13339     var m = {
13340         "\b": '\\b',
13341         "\t": '\\t',
13342         "\n": '\\n',
13343         "\f": '\\f',
13344         "\r": '\\r',
13345         '"' : '\\"',
13346         "\\": '\\\\'
13347     };
13348
13349     var encodeString = function(s){
13350         if (/["\\\x00-\x1f]/.test(s)) {
13351             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13352                 var c = m[b];
13353                 if(c){
13354                     return c;
13355                 }
13356                 c = b.charCodeAt();
13357                 return "\\u00" +
13358                     Math.floor(c / 16).toString(16) +
13359                     (c % 16).toString(16);
13360             }) + '"';
13361         }
13362         return '"' + s + '"';
13363     };
13364     
13365     var encodeArray = function(o){
13366         var a = ["["], b, i, l = o.length, v;
13367             for (i = 0; i < l; i += 1) {
13368                 v = o[i];
13369                 switch (typeof v) {
13370                     case "undefined":
13371                     case "function":
13372                     case "unknown":
13373                         break;
13374                     default:
13375                         if (b) {
13376                             a.push(',');
13377                         }
13378                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13379                         b = true;
13380                 }
13381             }
13382             a.push("]");
13383             return a.join("");
13384     };
13385     
13386     var encodeDate = function(o){
13387         return '"' + o.getFullYear() + "-" +
13388                 pad(o.getMonth() + 1) + "-" +
13389                 pad(o.getDate()) + "T" +
13390                 pad(o.getHours()) + ":" +
13391                 pad(o.getMinutes()) + ":" +
13392                 pad(o.getSeconds()) + '"';
13393     };
13394     
13395     /**
13396      * Encodes an Object, Array or other value
13397      * @param {Mixed} o The variable to encode
13398      * @return {String} The JSON string
13399      */
13400     this.encode = function(o)
13401     {
13402         // should this be extended to fully wrap stringify..
13403         
13404         if(typeof o == "undefined" || o === null){
13405             return "null";
13406         }else if(o instanceof Array){
13407             return encodeArray(o);
13408         }else if(o instanceof Date){
13409             return encodeDate(o);
13410         }else if(typeof o == "string"){
13411             return encodeString(o);
13412         }else if(typeof o == "number"){
13413             return isFinite(o) ? String(o) : "null";
13414         }else if(typeof o == "boolean"){
13415             return String(o);
13416         }else {
13417             var a = ["{"], b, i, v;
13418             for (i in o) {
13419                 if(!useHasOwn || o.hasOwnProperty(i)) {
13420                     v = o[i];
13421                     switch (typeof v) {
13422                     case "undefined":
13423                     case "function":
13424                     case "unknown":
13425                         break;
13426                     default:
13427                         if(b){
13428                             a.push(',');
13429                         }
13430                         a.push(this.encode(i), ":",
13431                                 v === null ? "null" : this.encode(v));
13432                         b = true;
13433                     }
13434                 }
13435             }
13436             a.push("}");
13437             return a.join("");
13438         }
13439     };
13440     
13441     /**
13442      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13443      * @param {String} json The JSON string
13444      * @return {Object} The resulting object
13445      */
13446     this.decode = function(json){
13447         
13448         return  /** eval:var:json */ eval("(" + json + ')');
13449     };
13450 })();
13451 /** 
13452  * Shorthand for {@link Roo.util.JSON#encode}
13453  * @member Roo encode 
13454  * @method */
13455 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13456 /** 
13457  * Shorthand for {@link Roo.util.JSON#decode}
13458  * @member Roo decode 
13459  * @method */
13460 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13461 /*
13462  * Based on:
13463  * Ext JS Library 1.1.1
13464  * Copyright(c) 2006-2007, Ext JS, LLC.
13465  *
13466  * Originally Released Under LGPL - original licence link has changed is not relivant.
13467  *
13468  * Fork - LGPL
13469  * <script type="text/javascript">
13470  */
13471  
13472 /**
13473  * @class Roo.util.Format
13474  * Reusable data formatting functions
13475  * @singleton
13476  */
13477 Roo.util.Format = function(){
13478     var trimRe = /^\s+|\s+$/g;
13479     return {
13480         /**
13481          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13482          * @param {String} value The string to truncate
13483          * @param {Number} length The maximum length to allow before truncating
13484          * @return {String} The converted text
13485          */
13486         ellipsis : function(value, len){
13487             if(value && value.length > len){
13488                 return value.substr(0, len-3)+"...";
13489             }
13490             return value;
13491         },
13492
13493         /**
13494          * Checks a reference and converts it to empty string if it is undefined
13495          * @param {Mixed} value Reference to check
13496          * @return {Mixed} Empty string if converted, otherwise the original value
13497          */
13498         undef : function(value){
13499             return typeof value != "undefined" ? value : "";
13500         },
13501
13502         /**
13503          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13504          * @param {String} value The string to encode
13505          * @return {String} The encoded text
13506          */
13507         htmlEncode : function(value){
13508             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13509         },
13510
13511         /**
13512          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13513          * @param {String} value The string to decode
13514          * @return {String} The decoded text
13515          */
13516         htmlDecode : function(value){
13517             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13518         },
13519
13520         /**
13521          * Trims any whitespace from either side of a string
13522          * @param {String} value The text to trim
13523          * @return {String} The trimmed text
13524          */
13525         trim : function(value){
13526             return String(value).replace(trimRe, "");
13527         },
13528
13529         /**
13530          * Returns a substring from within an original string
13531          * @param {String} value The original text
13532          * @param {Number} start The start index of the substring
13533          * @param {Number} length The length of the substring
13534          * @return {String} The substring
13535          */
13536         substr : function(value, start, length){
13537             return String(value).substr(start, length);
13538         },
13539
13540         /**
13541          * Converts a string to all lower case letters
13542          * @param {String} value The text to convert
13543          * @return {String} The converted text
13544          */
13545         lowercase : function(value){
13546             return String(value).toLowerCase();
13547         },
13548
13549         /**
13550          * Converts a string to all upper case letters
13551          * @param {String} value The text to convert
13552          * @return {String} The converted text
13553          */
13554         uppercase : function(value){
13555             return String(value).toUpperCase();
13556         },
13557
13558         /**
13559          * Converts the first character only of a string to upper case
13560          * @param {String} value The text to convert
13561          * @return {String} The converted text
13562          */
13563         capitalize : function(value){
13564             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13565         },
13566
13567         // private
13568         call : function(value, fn){
13569             if(arguments.length > 2){
13570                 var args = Array.prototype.slice.call(arguments, 2);
13571                 args.unshift(value);
13572                  
13573                 return /** eval:var:value */  eval(fn).apply(window, args);
13574             }else{
13575                 /** eval:var:value */
13576                 return /** eval:var:value */ eval(fn).call(window, value);
13577             }
13578         },
13579
13580        
13581         /**
13582          * safer version of Math.toFixed..??/
13583          * @param {Number/String} value The numeric value to format
13584          * @param {Number/String} value Decimal places 
13585          * @return {String} The formatted currency string
13586          */
13587         toFixed : function(v, n)
13588         {
13589             // why not use to fixed - precision is buggered???
13590             if (!n) {
13591                 return Math.round(v-0);
13592             }
13593             var fact = Math.pow(10,n+1);
13594             v = (Math.round((v-0)*fact))/fact;
13595             var z = (''+fact).substring(2);
13596             if (v == Math.floor(v)) {
13597                 return Math.floor(v) + '.' + z;
13598             }
13599             
13600             // now just padd decimals..
13601             var ps = String(v).split('.');
13602             var fd = (ps[1] + z);
13603             var r = fd.substring(0,n); 
13604             var rm = fd.substring(n); 
13605             if (rm < 5) {
13606                 return ps[0] + '.' + r;
13607             }
13608             r*=1; // turn it into a number;
13609             r++;
13610             if (String(r).length != n) {
13611                 ps[0]*=1;
13612                 ps[0]++;
13613                 r = String(r).substring(1); // chop the end off.
13614             }
13615             
13616             return ps[0] + '.' + r;
13617              
13618         },
13619         
13620         /**
13621          * Format a number as US currency
13622          * @param {Number/String} value The numeric value to format
13623          * @return {String} The formatted currency string
13624          */
13625         usMoney : function(v){
13626             return '$' + Roo.util.Format.number(v);
13627         },
13628         
13629         /**
13630          * Format a number
13631          * eventually this should probably emulate php's number_format
13632          * @param {Number/String} value The numeric value to format
13633          * @param {Number} decimals number of decimal places
13634          * @return {String} The formatted currency string
13635          */
13636         number : function(v,decimals)
13637         {
13638             // multiply and round.
13639             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13640             var mul = Math.pow(10, decimals);
13641             var zero = String(mul).substring(1);
13642             v = (Math.round((v-0)*mul))/mul;
13643             
13644             // if it's '0' number.. then
13645             
13646             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13647             v = String(v);
13648             var ps = v.split('.');
13649             var whole = ps[0];
13650             
13651             
13652             var r = /(\d+)(\d{3})/;
13653             // add comma's
13654             while (r.test(whole)) {
13655                 whole = whole.replace(r, '$1' + ',' + '$2');
13656             }
13657             
13658             
13659             var sub = ps[1] ?
13660                     // has decimals..
13661                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13662                     // does not have decimals
13663                     (decimals ? ('.' + zero) : '');
13664             
13665             
13666             return whole + sub ;
13667         },
13668         
13669         /**
13670          * Parse a value into a formatted date using the specified format pattern.
13671          * @param {Mixed} value The value to format
13672          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13673          * @return {String} The formatted date string
13674          */
13675         date : function(v, format){
13676             if(!v){
13677                 return "";
13678             }
13679             if(!(v instanceof Date)){
13680                 v = new Date(Date.parse(v));
13681             }
13682             return v.dateFormat(format || Roo.util.Format.defaults.date);
13683         },
13684
13685         /**
13686          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13687          * @param {String} format Any valid date format string
13688          * @return {Function} The date formatting function
13689          */
13690         dateRenderer : function(format){
13691             return function(v){
13692                 return Roo.util.Format.date(v, format);  
13693             };
13694         },
13695
13696         // private
13697         stripTagsRE : /<\/?[^>]+>/gi,
13698         
13699         /**
13700          * Strips all HTML tags
13701          * @param {Mixed} value The text from which to strip tags
13702          * @return {String} The stripped text
13703          */
13704         stripTags : function(v){
13705             return !v ? v : String(v).replace(this.stripTagsRE, "");
13706         }
13707     };
13708 }();
13709 Roo.util.Format.defaults = {
13710     date : 'd/M/Y'
13711 };/*
13712  * Based on:
13713  * Ext JS Library 1.1.1
13714  * Copyright(c) 2006-2007, Ext JS, LLC.
13715  *
13716  * Originally Released Under LGPL - original licence link has changed is not relivant.
13717  *
13718  * Fork - LGPL
13719  * <script type="text/javascript">
13720  */
13721
13722
13723  
13724
13725 /**
13726  * @class Roo.MasterTemplate
13727  * @extends Roo.Template
13728  * Provides a template that can have child templates. The syntax is:
13729 <pre><code>
13730 var t = new Roo.MasterTemplate(
13731         '&lt;select name="{name}"&gt;',
13732                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13733         '&lt;/select&gt;'
13734 );
13735 t.add('options', {value: 'foo', text: 'bar'});
13736 // or you can add multiple child elements in one shot
13737 t.addAll('options', [
13738     {value: 'foo', text: 'bar'},
13739     {value: 'foo2', text: 'bar2'},
13740     {value: 'foo3', text: 'bar3'}
13741 ]);
13742 // then append, applying the master template values
13743 t.append('my-form', {name: 'my-select'});
13744 </code></pre>
13745 * A name attribute for the child template is not required if you have only one child
13746 * template or you want to refer to them by index.
13747  */
13748 Roo.MasterTemplate = function(){
13749     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13750     this.originalHtml = this.html;
13751     var st = {};
13752     var m, re = this.subTemplateRe;
13753     re.lastIndex = 0;
13754     var subIndex = 0;
13755     while(m = re.exec(this.html)){
13756         var name = m[1], content = m[2];
13757         st[subIndex] = {
13758             name: name,
13759             index: subIndex,
13760             buffer: [],
13761             tpl : new Roo.Template(content)
13762         };
13763         if(name){
13764             st[name] = st[subIndex];
13765         }
13766         st[subIndex].tpl.compile();
13767         st[subIndex].tpl.call = this.call.createDelegate(this);
13768         subIndex++;
13769     }
13770     this.subCount = subIndex;
13771     this.subs = st;
13772 };
13773 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13774     /**
13775     * The regular expression used to match sub templates
13776     * @type RegExp
13777     * @property
13778     */
13779     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13780
13781     /**
13782      * Applies the passed values to a child template.
13783      * @param {String/Number} name (optional) The name or index of the child template
13784      * @param {Array/Object} values The values to be applied to the template
13785      * @return {MasterTemplate} this
13786      */
13787      add : function(name, values){
13788         if(arguments.length == 1){
13789             values = arguments[0];
13790             name = 0;
13791         }
13792         var s = this.subs[name];
13793         s.buffer[s.buffer.length] = s.tpl.apply(values);
13794         return this;
13795     },
13796
13797     /**
13798      * Applies all the passed values to a child template.
13799      * @param {String/Number} name (optional) The name or index of the child template
13800      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13801      * @param {Boolean} reset (optional) True to reset the template first
13802      * @return {MasterTemplate} this
13803      */
13804     fill : function(name, values, reset){
13805         var a = arguments;
13806         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13807             values = a[0];
13808             name = 0;
13809             reset = a[1];
13810         }
13811         if(reset){
13812             this.reset();
13813         }
13814         for(var i = 0, len = values.length; i < len; i++){
13815             this.add(name, values[i]);
13816         }
13817         return this;
13818     },
13819
13820     /**
13821      * Resets the template for reuse
13822      * @return {MasterTemplate} this
13823      */
13824      reset : function(){
13825         var s = this.subs;
13826         for(var i = 0; i < this.subCount; i++){
13827             s[i].buffer = [];
13828         }
13829         return this;
13830     },
13831
13832     applyTemplate : function(values){
13833         var s = this.subs;
13834         var replaceIndex = -1;
13835         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13836             return s[++replaceIndex].buffer.join("");
13837         });
13838         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13839     },
13840
13841     apply : function(){
13842         return this.applyTemplate.apply(this, arguments);
13843     },
13844
13845     compile : function(){return this;}
13846 });
13847
13848 /**
13849  * Alias for fill().
13850  * @method
13851  */
13852 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13853  /**
13854  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13855  * var tpl = Roo.MasterTemplate.from('element-id');
13856  * @param {String/HTMLElement} el
13857  * @param {Object} config
13858  * @static
13859  */
13860 Roo.MasterTemplate.from = function(el, config){
13861     el = Roo.getDom(el);
13862     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13863 };/*
13864  * Based on:
13865  * Ext JS Library 1.1.1
13866  * Copyright(c) 2006-2007, Ext JS, LLC.
13867  *
13868  * Originally Released Under LGPL - original licence link has changed is not relivant.
13869  *
13870  * Fork - LGPL
13871  * <script type="text/javascript">
13872  */
13873
13874  
13875 /**
13876  * @class Roo.util.CSS
13877  * Utility class for manipulating CSS rules
13878  * @singleton
13879  */
13880 Roo.util.CSS = function(){
13881         var rules = null;
13882         var doc = document;
13883
13884     var camelRe = /(-[a-z])/gi;
13885     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13886
13887    return {
13888    /**
13889     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13890     * tag and appended to the HEAD of the document.
13891     * @param {String|Object} cssText The text containing the css rules
13892     * @param {String} id An id to add to the stylesheet for later removal
13893     * @return {StyleSheet}
13894     */
13895     createStyleSheet : function(cssText, id){
13896         var ss;
13897         var head = doc.getElementsByTagName("head")[0];
13898         var nrules = doc.createElement("style");
13899         nrules.setAttribute("type", "text/css");
13900         if(id){
13901             nrules.setAttribute("id", id);
13902         }
13903         if (typeof(cssText) != 'string') {
13904             // support object maps..
13905             // not sure if this a good idea.. 
13906             // perhaps it should be merged with the general css handling
13907             // and handle js style props.
13908             var cssTextNew = [];
13909             for(var n in cssText) {
13910                 var citems = [];
13911                 for(var k in cssText[n]) {
13912                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13913                 }
13914                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13915                 
13916             }
13917             cssText = cssTextNew.join("\n");
13918             
13919         }
13920        
13921        
13922        if(Roo.isIE){
13923            head.appendChild(nrules);
13924            ss = nrules.styleSheet;
13925            ss.cssText = cssText;
13926        }else{
13927            try{
13928                 nrules.appendChild(doc.createTextNode(cssText));
13929            }catch(e){
13930                nrules.cssText = cssText; 
13931            }
13932            head.appendChild(nrules);
13933            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13934        }
13935        this.cacheStyleSheet(ss);
13936        return ss;
13937    },
13938
13939    /**
13940     * Removes a style or link tag by id
13941     * @param {String} id The id of the tag
13942     */
13943    removeStyleSheet : function(id){
13944        var existing = doc.getElementById(id);
13945        if(existing){
13946            existing.parentNode.removeChild(existing);
13947        }
13948    },
13949
13950    /**
13951     * Dynamically swaps an existing stylesheet reference for a new one
13952     * @param {String} id The id of an existing link tag to remove
13953     * @param {String} url The href of the new stylesheet to include
13954     */
13955    swapStyleSheet : function(id, url){
13956        this.removeStyleSheet(id);
13957        var ss = doc.createElement("link");
13958        ss.setAttribute("rel", "stylesheet");
13959        ss.setAttribute("type", "text/css");
13960        ss.setAttribute("id", id);
13961        ss.setAttribute("href", url);
13962        doc.getElementsByTagName("head")[0].appendChild(ss);
13963    },
13964    
13965    /**
13966     * Refresh the rule cache if you have dynamically added stylesheets
13967     * @return {Object} An object (hash) of rules indexed by selector
13968     */
13969    refreshCache : function(){
13970        return this.getRules(true);
13971    },
13972
13973    // private
13974    cacheStyleSheet : function(stylesheet){
13975        if(!rules){
13976            rules = {};
13977        }
13978        try{// try catch for cross domain access issue
13979            var ssRules = stylesheet.cssRules || stylesheet.rules;
13980            for(var j = ssRules.length-1; j >= 0; --j){
13981                rules[ssRules[j].selectorText] = ssRules[j];
13982            }
13983        }catch(e){}
13984    },
13985    
13986    /**
13987     * Gets all css rules for the document
13988     * @param {Boolean} refreshCache true to refresh the internal cache
13989     * @return {Object} An object (hash) of rules indexed by selector
13990     */
13991    getRules : function(refreshCache){
13992                 if(rules == null || refreshCache){
13993                         rules = {};
13994                         var ds = doc.styleSheets;
13995                         for(var i =0, len = ds.length; i < len; i++){
13996                             try{
13997                         this.cacheStyleSheet(ds[i]);
13998                     }catch(e){} 
13999                 }
14000                 }
14001                 return rules;
14002         },
14003         
14004         /**
14005     * Gets an an individual CSS rule by selector(s)
14006     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14007     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14008     * @return {CSSRule} The CSS rule or null if one is not found
14009     */
14010    getRule : function(selector, refreshCache){
14011                 var rs = this.getRules(refreshCache);
14012                 if(!(selector instanceof Array)){
14013                     return rs[selector];
14014                 }
14015                 for(var i = 0; i < selector.length; i++){
14016                         if(rs[selector[i]]){
14017                                 return rs[selector[i]];
14018                         }
14019                 }
14020                 return null;
14021         },
14022         
14023         
14024         /**
14025     * Updates a rule property
14026     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14027     * @param {String} property The css property
14028     * @param {String} value The new value for the property
14029     * @return {Boolean} true If a rule was found and updated
14030     */
14031    updateRule : function(selector, property, value){
14032                 if(!(selector instanceof Array)){
14033                         var rule = this.getRule(selector);
14034                         if(rule){
14035                                 rule.style[property.replace(camelRe, camelFn)] = value;
14036                                 return true;
14037                         }
14038                 }else{
14039                         for(var i = 0; i < selector.length; i++){
14040                                 if(this.updateRule(selector[i], property, value)){
14041                                         return true;
14042                                 }
14043                         }
14044                 }
14045                 return false;
14046         }
14047    };   
14048 }();/*
14049  * Based on:
14050  * Ext JS Library 1.1.1
14051  * Copyright(c) 2006-2007, Ext JS, LLC.
14052  *
14053  * Originally Released Under LGPL - original licence link has changed is not relivant.
14054  *
14055  * Fork - LGPL
14056  * <script type="text/javascript">
14057  */
14058
14059  
14060
14061 /**
14062  * @class Roo.util.ClickRepeater
14063  * @extends Roo.util.Observable
14064  * 
14065  * A wrapper class which can be applied to any element. Fires a "click" event while the
14066  * mouse is pressed. The interval between firings may be specified in the config but
14067  * defaults to 10 milliseconds.
14068  * 
14069  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14070  * 
14071  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14072  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14073  * Similar to an autorepeat key delay.
14074  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14075  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14076  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14077  *           "interval" and "delay" are ignored. "immediate" is honored.
14078  * @cfg {Boolean} preventDefault True to prevent the default click event
14079  * @cfg {Boolean} stopDefault True to stop the default click event
14080  * 
14081  * @history
14082  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14083  *     2007-02-02 jvs Renamed to ClickRepeater
14084  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14085  *
14086  *  @constructor
14087  * @param {String/HTMLElement/Element} el The element to listen on
14088  * @param {Object} config
14089  **/
14090 Roo.util.ClickRepeater = function(el, config)
14091 {
14092     this.el = Roo.get(el);
14093     this.el.unselectable();
14094
14095     Roo.apply(this, config);
14096
14097     this.addEvents({
14098     /**
14099      * @event mousedown
14100      * Fires when the mouse button is depressed.
14101      * @param {Roo.util.ClickRepeater} this
14102      */
14103         "mousedown" : true,
14104     /**
14105      * @event click
14106      * Fires on a specified interval during the time the element is pressed.
14107      * @param {Roo.util.ClickRepeater} this
14108      */
14109         "click" : true,
14110     /**
14111      * @event mouseup
14112      * Fires when the mouse key is released.
14113      * @param {Roo.util.ClickRepeater} this
14114      */
14115         "mouseup" : true
14116     });
14117
14118     this.el.on("mousedown", this.handleMouseDown, this);
14119     if(this.preventDefault || this.stopDefault){
14120         this.el.on("click", function(e){
14121             if(this.preventDefault){
14122                 e.preventDefault();
14123             }
14124             if(this.stopDefault){
14125                 e.stopEvent();
14126             }
14127         }, this);
14128     }
14129
14130     // allow inline handler
14131     if(this.handler){
14132         this.on("click", this.handler,  this.scope || this);
14133     }
14134
14135     Roo.util.ClickRepeater.superclass.constructor.call(this);
14136 };
14137
14138 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14139     interval : 20,
14140     delay: 250,
14141     preventDefault : true,
14142     stopDefault : false,
14143     timer : 0,
14144
14145     // private
14146     handleMouseDown : function(){
14147         clearTimeout(this.timer);
14148         this.el.blur();
14149         if(this.pressClass){
14150             this.el.addClass(this.pressClass);
14151         }
14152         this.mousedownTime = new Date();
14153
14154         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14155         this.el.on("mouseout", this.handleMouseOut, this);
14156
14157         this.fireEvent("mousedown", this);
14158         this.fireEvent("click", this);
14159         
14160         this.timer = this.click.defer(this.delay || this.interval, this);
14161     },
14162
14163     // private
14164     click : function(){
14165         this.fireEvent("click", this);
14166         this.timer = this.click.defer(this.getInterval(), this);
14167     },
14168
14169     // private
14170     getInterval: function(){
14171         if(!this.accelerate){
14172             return this.interval;
14173         }
14174         var pressTime = this.mousedownTime.getElapsed();
14175         if(pressTime < 500){
14176             return 400;
14177         }else if(pressTime < 1700){
14178             return 320;
14179         }else if(pressTime < 2600){
14180             return 250;
14181         }else if(pressTime < 3500){
14182             return 180;
14183         }else if(pressTime < 4400){
14184             return 140;
14185         }else if(pressTime < 5300){
14186             return 80;
14187         }else if(pressTime < 6200){
14188             return 50;
14189         }else{
14190             return 10;
14191         }
14192     },
14193
14194     // private
14195     handleMouseOut : function(){
14196         clearTimeout(this.timer);
14197         if(this.pressClass){
14198             this.el.removeClass(this.pressClass);
14199         }
14200         this.el.on("mouseover", this.handleMouseReturn, this);
14201     },
14202
14203     // private
14204     handleMouseReturn : function(){
14205         this.el.un("mouseover", this.handleMouseReturn);
14206         if(this.pressClass){
14207             this.el.addClass(this.pressClass);
14208         }
14209         this.click();
14210     },
14211
14212     // private
14213     handleMouseUp : function(){
14214         clearTimeout(this.timer);
14215         this.el.un("mouseover", this.handleMouseReturn);
14216         this.el.un("mouseout", this.handleMouseOut);
14217         Roo.get(document).un("mouseup", this.handleMouseUp);
14218         this.el.removeClass(this.pressClass);
14219         this.fireEvent("mouseup", this);
14220     }
14221 });/*
14222  * Based on:
14223  * Ext JS Library 1.1.1
14224  * Copyright(c) 2006-2007, Ext JS, LLC.
14225  *
14226  * Originally Released Under LGPL - original licence link has changed is not relivant.
14227  *
14228  * Fork - LGPL
14229  * <script type="text/javascript">
14230  */
14231
14232  
14233 /**
14234  * @class Roo.KeyNav
14235  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14236  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14237  * way to implement custom navigation schemes for any UI component.</p>
14238  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14239  * pageUp, pageDown, del, home, end.  Usage:</p>
14240  <pre><code>
14241 var nav = new Roo.KeyNav("my-element", {
14242     "left" : function(e){
14243         this.moveLeft(e.ctrlKey);
14244     },
14245     "right" : function(e){
14246         this.moveRight(e.ctrlKey);
14247     },
14248     "enter" : function(e){
14249         this.save();
14250     },
14251     scope : this
14252 });
14253 </code></pre>
14254  * @constructor
14255  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14256  * @param {Object} config The config
14257  */
14258 Roo.KeyNav = function(el, config){
14259     this.el = Roo.get(el);
14260     Roo.apply(this, config);
14261     if(!this.disabled){
14262         this.disabled = true;
14263         this.enable();
14264     }
14265 };
14266
14267 Roo.KeyNav.prototype = {
14268     /**
14269      * @cfg {Boolean} disabled
14270      * True to disable this KeyNav instance (defaults to false)
14271      */
14272     disabled : false,
14273     /**
14274      * @cfg {String} defaultEventAction
14275      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14276      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14277      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14278      */
14279     defaultEventAction: "stopEvent",
14280     /**
14281      * @cfg {Boolean} forceKeyDown
14282      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14283      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14284      * handle keydown instead of keypress.
14285      */
14286     forceKeyDown : false,
14287
14288     // private
14289     prepareEvent : function(e){
14290         var k = e.getKey();
14291         var h = this.keyToHandler[k];
14292         //if(h && this[h]){
14293         //    e.stopPropagation();
14294         //}
14295         if(Roo.isSafari && h && k >= 37 && k <= 40){
14296             e.stopEvent();
14297         }
14298     },
14299
14300     // private
14301     relay : function(e){
14302         var k = e.getKey();
14303         var h = this.keyToHandler[k];
14304         if(h && this[h]){
14305             if(this.doRelay(e, this[h], h) !== true){
14306                 e[this.defaultEventAction]();
14307             }
14308         }
14309     },
14310
14311     // private
14312     doRelay : function(e, h, hname){
14313         return h.call(this.scope || this, e);
14314     },
14315
14316     // possible handlers
14317     enter : false,
14318     left : false,
14319     right : false,
14320     up : false,
14321     down : false,
14322     tab : false,
14323     esc : false,
14324     pageUp : false,
14325     pageDown : false,
14326     del : false,
14327     home : false,
14328     end : false,
14329
14330     // quick lookup hash
14331     keyToHandler : {
14332         37 : "left",
14333         39 : "right",
14334         38 : "up",
14335         40 : "down",
14336         33 : "pageUp",
14337         34 : "pageDown",
14338         46 : "del",
14339         36 : "home",
14340         35 : "end",
14341         13 : "enter",
14342         27 : "esc",
14343         9  : "tab"
14344     },
14345
14346         /**
14347          * Enable this KeyNav
14348          */
14349         enable: function(){
14350                 if(this.disabled){
14351             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14352             // the EventObject will normalize Safari automatically
14353             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14354                 this.el.on("keydown", this.relay,  this);
14355             }else{
14356                 this.el.on("keydown", this.prepareEvent,  this);
14357                 this.el.on("keypress", this.relay,  this);
14358             }
14359                     this.disabled = false;
14360                 }
14361         },
14362
14363         /**
14364          * Disable this KeyNav
14365          */
14366         disable: function(){
14367                 if(!this.disabled){
14368                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14369                 this.el.un("keydown", this.relay);
14370             }else{
14371                 this.el.un("keydown", this.prepareEvent);
14372                 this.el.un("keypress", this.relay);
14373             }
14374                     this.disabled = true;
14375                 }
14376         }
14377 };/*
14378  * Based on:
14379  * Ext JS Library 1.1.1
14380  * Copyright(c) 2006-2007, Ext JS, LLC.
14381  *
14382  * Originally Released Under LGPL - original licence link has changed is not relivant.
14383  *
14384  * Fork - LGPL
14385  * <script type="text/javascript">
14386  */
14387
14388  
14389 /**
14390  * @class Roo.KeyMap
14391  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14392  * The constructor accepts the same config object as defined by {@link #addBinding}.
14393  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14394  * combination it will call the function with this signature (if the match is a multi-key
14395  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14396  * A KeyMap can also handle a string representation of keys.<br />
14397  * Usage:
14398  <pre><code>
14399 // map one key by key code
14400 var map = new Roo.KeyMap("my-element", {
14401     key: 13, // or Roo.EventObject.ENTER
14402     fn: myHandler,
14403     scope: myObject
14404 });
14405
14406 // map multiple keys to one action by string
14407 var map = new Roo.KeyMap("my-element", {
14408     key: "a\r\n\t",
14409     fn: myHandler,
14410     scope: myObject
14411 });
14412
14413 // map multiple keys to multiple actions by strings and array of codes
14414 var map = new Roo.KeyMap("my-element", [
14415     {
14416         key: [10,13],
14417         fn: function(){ alert("Return was pressed"); }
14418     }, {
14419         key: "abc",
14420         fn: function(){ alert('a, b or c was pressed'); }
14421     }, {
14422         key: "\t",
14423         ctrl:true,
14424         shift:true,
14425         fn: function(){ alert('Control + shift + tab was pressed.'); }
14426     }
14427 ]);
14428 </code></pre>
14429  * <b>Note: A KeyMap starts enabled</b>
14430  * @constructor
14431  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14432  * @param {Object} config The config (see {@link #addBinding})
14433  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14434  */
14435 Roo.KeyMap = function(el, config, eventName){
14436     this.el  = Roo.get(el);
14437     this.eventName = eventName || "keydown";
14438     this.bindings = [];
14439     if(config){
14440         this.addBinding(config);
14441     }
14442     this.enable();
14443 };
14444
14445 Roo.KeyMap.prototype = {
14446     /**
14447      * True to stop the event from bubbling and prevent the default browser action if the
14448      * key was handled by the KeyMap (defaults to false)
14449      * @type Boolean
14450      */
14451     stopEvent : false,
14452
14453     /**
14454      * Add a new binding to this KeyMap. The following config object properties are supported:
14455      * <pre>
14456 Property    Type             Description
14457 ----------  ---------------  ----------------------------------------------------------------------
14458 key         String/Array     A single keycode or an array of keycodes to handle
14459 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14460 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14461 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14462 fn          Function         The function to call when KeyMap finds the expected key combination
14463 scope       Object           The scope of the callback function
14464 </pre>
14465      *
14466      * Usage:
14467      * <pre><code>
14468 // Create a KeyMap
14469 var map = new Roo.KeyMap(document, {
14470     key: Roo.EventObject.ENTER,
14471     fn: handleKey,
14472     scope: this
14473 });
14474
14475 //Add a new binding to the existing KeyMap later
14476 map.addBinding({
14477     key: 'abc',
14478     shift: true,
14479     fn: handleKey,
14480     scope: this
14481 });
14482 </code></pre>
14483      * @param {Object/Array} config A single KeyMap config or an array of configs
14484      */
14485         addBinding : function(config){
14486         if(config instanceof Array){
14487             for(var i = 0, len = config.length; i < len; i++){
14488                 this.addBinding(config[i]);
14489             }
14490             return;
14491         }
14492         var keyCode = config.key,
14493             shift = config.shift, 
14494             ctrl = config.ctrl, 
14495             alt = config.alt,
14496             fn = config.fn,
14497             scope = config.scope;
14498         if(typeof keyCode == "string"){
14499             var ks = [];
14500             var keyString = keyCode.toUpperCase();
14501             for(var j = 0, len = keyString.length; j < len; j++){
14502                 ks.push(keyString.charCodeAt(j));
14503             }
14504             keyCode = ks;
14505         }
14506         var keyArray = keyCode instanceof Array;
14507         var handler = function(e){
14508             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14509                 var k = e.getKey();
14510                 if(keyArray){
14511                     for(var i = 0, len = keyCode.length; i < len; i++){
14512                         if(keyCode[i] == k){
14513                           if(this.stopEvent){
14514                               e.stopEvent();
14515                           }
14516                           fn.call(scope || window, k, e);
14517                           return;
14518                         }
14519                     }
14520                 }else{
14521                     if(k == keyCode){
14522                         if(this.stopEvent){
14523                            e.stopEvent();
14524                         }
14525                         fn.call(scope || window, k, e);
14526                     }
14527                 }
14528             }
14529         };
14530         this.bindings.push(handler);  
14531         },
14532
14533     /**
14534      * Shorthand for adding a single key listener
14535      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14536      * following options:
14537      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14538      * @param {Function} fn The function to call
14539      * @param {Object} scope (optional) The scope of the function
14540      */
14541     on : function(key, fn, scope){
14542         var keyCode, shift, ctrl, alt;
14543         if(typeof key == "object" && !(key instanceof Array)){
14544             keyCode = key.key;
14545             shift = key.shift;
14546             ctrl = key.ctrl;
14547             alt = key.alt;
14548         }else{
14549             keyCode = key;
14550         }
14551         this.addBinding({
14552             key: keyCode,
14553             shift: shift,
14554             ctrl: ctrl,
14555             alt: alt,
14556             fn: fn,
14557             scope: scope
14558         })
14559     },
14560
14561     // private
14562     handleKeyDown : function(e){
14563             if(this.enabled){ //just in case
14564             var b = this.bindings;
14565             for(var i = 0, len = b.length; i < len; i++){
14566                 b[i].call(this, e);
14567             }
14568             }
14569         },
14570         
14571         /**
14572          * Returns true if this KeyMap is enabled
14573          * @return {Boolean} 
14574          */
14575         isEnabled : function(){
14576             return this.enabled;  
14577         },
14578         
14579         /**
14580          * Enables this KeyMap
14581          */
14582         enable: function(){
14583                 if(!this.enabled){
14584                     this.el.on(this.eventName, this.handleKeyDown, this);
14585                     this.enabled = true;
14586                 }
14587         },
14588
14589         /**
14590          * Disable this KeyMap
14591          */
14592         disable: function(){
14593                 if(this.enabled){
14594                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14595                     this.enabled = false;
14596                 }
14597         }
14598 };/*
14599  * Based on:
14600  * Ext JS Library 1.1.1
14601  * Copyright(c) 2006-2007, Ext JS, LLC.
14602  *
14603  * Originally Released Under LGPL - original licence link has changed is not relivant.
14604  *
14605  * Fork - LGPL
14606  * <script type="text/javascript">
14607  */
14608
14609  
14610 /**
14611  * @class Roo.util.TextMetrics
14612  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14613  * wide, in pixels, a given block of text will be.
14614  * @singleton
14615  */
14616 Roo.util.TextMetrics = function(){
14617     var shared;
14618     return {
14619         /**
14620          * Measures the size of the specified text
14621          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14622          * that can affect the size of the rendered text
14623          * @param {String} text The text to measure
14624          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14625          * in order to accurately measure the text height
14626          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14627          */
14628         measure : function(el, text, fixedWidth){
14629             if(!shared){
14630                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14631             }
14632             shared.bind(el);
14633             shared.setFixedWidth(fixedWidth || 'auto');
14634             return shared.getSize(text);
14635         },
14636
14637         /**
14638          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14639          * the overhead of multiple calls to initialize the style properties on each measurement.
14640          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14641          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14642          * in order to accurately measure the text height
14643          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14644          */
14645         createInstance : function(el, fixedWidth){
14646             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14647         }
14648     };
14649 }();
14650
14651  
14652
14653 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14654     var ml = new Roo.Element(document.createElement('div'));
14655     document.body.appendChild(ml.dom);
14656     ml.position('absolute');
14657     ml.setLeftTop(-1000, -1000);
14658     ml.hide();
14659
14660     if(fixedWidth){
14661         ml.setWidth(fixedWidth);
14662     }
14663      
14664     var instance = {
14665         /**
14666          * Returns the size of the specified text based on the internal element's style and width properties
14667          * @memberOf Roo.util.TextMetrics.Instance#
14668          * @param {String} text The text to measure
14669          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14670          */
14671         getSize : function(text){
14672             ml.update(text);
14673             var s = ml.getSize();
14674             ml.update('');
14675             return s;
14676         },
14677
14678         /**
14679          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14680          * that can affect the size of the rendered text
14681          * @memberOf Roo.util.TextMetrics.Instance#
14682          * @param {String/HTMLElement} el The element, dom node or id
14683          */
14684         bind : function(el){
14685             ml.setStyle(
14686                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14687             );
14688         },
14689
14690         /**
14691          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14692          * to set a fixed width in order to accurately measure the text height.
14693          * @memberOf Roo.util.TextMetrics.Instance#
14694          * @param {Number} width The width to set on the element
14695          */
14696         setFixedWidth : function(width){
14697             ml.setWidth(width);
14698         },
14699
14700         /**
14701          * Returns the measured width of the specified text
14702          * @memberOf Roo.util.TextMetrics.Instance#
14703          * @param {String} text The text to measure
14704          * @return {Number} width The width in pixels
14705          */
14706         getWidth : function(text){
14707             ml.dom.style.width = 'auto';
14708             return this.getSize(text).width;
14709         },
14710
14711         /**
14712          * Returns the measured height of the specified text.  For multiline text, be sure to call
14713          * {@link #setFixedWidth} if necessary.
14714          * @memberOf Roo.util.TextMetrics.Instance#
14715          * @param {String} text The text to measure
14716          * @return {Number} height The height in pixels
14717          */
14718         getHeight : function(text){
14719             return this.getSize(text).height;
14720         }
14721     };
14722
14723     instance.bind(bindTo);
14724
14725     return instance;
14726 };
14727
14728 // backwards compat
14729 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14730  * Based on:
14731  * Ext JS Library 1.1.1
14732  * Copyright(c) 2006-2007, Ext JS, LLC.
14733  *
14734  * Originally Released Under LGPL - original licence link has changed is not relivant.
14735  *
14736  * Fork - LGPL
14737  * <script type="text/javascript">
14738  */
14739
14740 /**
14741  * @class Roo.state.Provider
14742  * Abstract base class for state provider implementations. This class provides methods
14743  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14744  * Provider interface.
14745  */
14746 Roo.state.Provider = function(){
14747     /**
14748      * @event statechange
14749      * Fires when a state change occurs.
14750      * @param {Provider} this This state provider
14751      * @param {String} key The state key which was changed
14752      * @param {String} value The encoded value for the state
14753      */
14754     this.addEvents({
14755         "statechange": true
14756     });
14757     this.state = {};
14758     Roo.state.Provider.superclass.constructor.call(this);
14759 };
14760 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14761     /**
14762      * Returns the current value for a key
14763      * @param {String} name The key name
14764      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14765      * @return {Mixed} The state data
14766      */
14767     get : function(name, defaultValue){
14768         return typeof this.state[name] == "undefined" ?
14769             defaultValue : this.state[name];
14770     },
14771     
14772     /**
14773      * Clears a value from the state
14774      * @param {String} name The key name
14775      */
14776     clear : function(name){
14777         delete this.state[name];
14778         this.fireEvent("statechange", this, name, null);
14779     },
14780     
14781     /**
14782      * Sets the value for a key
14783      * @param {String} name The key name
14784      * @param {Mixed} value The value to set
14785      */
14786     set : function(name, value){
14787         this.state[name] = value;
14788         this.fireEvent("statechange", this, name, value);
14789     },
14790     
14791     /**
14792      * Decodes a string previously encoded with {@link #encodeValue}.
14793      * @param {String} value The value to decode
14794      * @return {Mixed} The decoded value
14795      */
14796     decodeValue : function(cookie){
14797         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14798         var matches = re.exec(unescape(cookie));
14799         if(!matches || !matches[1]) return; // non state cookie
14800         var type = matches[1];
14801         var v = matches[2];
14802         switch(type){
14803             case "n":
14804                 return parseFloat(v);
14805             case "d":
14806                 return new Date(Date.parse(v));
14807             case "b":
14808                 return (v == "1");
14809             case "a":
14810                 var all = [];
14811                 var values = v.split("^");
14812                 for(var i = 0, len = values.length; i < len; i++){
14813                     all.push(this.decodeValue(values[i]));
14814                 }
14815                 return all;
14816            case "o":
14817                 var all = {};
14818                 var values = v.split("^");
14819                 for(var i = 0, len = values.length; i < len; i++){
14820                     var kv = values[i].split("=");
14821                     all[kv[0]] = this.decodeValue(kv[1]);
14822                 }
14823                 return all;
14824            default:
14825                 return v;
14826         }
14827     },
14828     
14829     /**
14830      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14831      * @param {Mixed} value The value to encode
14832      * @return {String} The encoded value
14833      */
14834     encodeValue : function(v){
14835         var enc;
14836         if(typeof v == "number"){
14837             enc = "n:" + v;
14838         }else if(typeof v == "boolean"){
14839             enc = "b:" + (v ? "1" : "0");
14840         }else if(v instanceof Date){
14841             enc = "d:" + v.toGMTString();
14842         }else if(v instanceof Array){
14843             var flat = "";
14844             for(var i = 0, len = v.length; i < len; i++){
14845                 flat += this.encodeValue(v[i]);
14846                 if(i != len-1) flat += "^";
14847             }
14848             enc = "a:" + flat;
14849         }else if(typeof v == "object"){
14850             var flat = "";
14851             for(var key in v){
14852                 if(typeof v[key] != "function"){
14853                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14854                 }
14855             }
14856             enc = "o:" + flat.substring(0, flat.length-1);
14857         }else{
14858             enc = "s:" + v;
14859         }
14860         return escape(enc);        
14861     }
14862 });
14863
14864 /*
14865  * Based on:
14866  * Ext JS Library 1.1.1
14867  * Copyright(c) 2006-2007, Ext JS, LLC.
14868  *
14869  * Originally Released Under LGPL - original licence link has changed is not relivant.
14870  *
14871  * Fork - LGPL
14872  * <script type="text/javascript">
14873  */
14874 /**
14875  * @class Roo.state.Manager
14876  * This is the global state manager. By default all components that are "state aware" check this class
14877  * for state information if you don't pass them a custom state provider. In order for this class
14878  * to be useful, it must be initialized with a provider when your application initializes.
14879  <pre><code>
14880 // in your initialization function
14881 init : function(){
14882    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14883    ...
14884    // supposed you have a {@link Roo.BorderLayout}
14885    var layout = new Roo.BorderLayout(...);
14886    layout.restoreState();
14887    // or a {Roo.BasicDialog}
14888    var dialog = new Roo.BasicDialog(...);
14889    dialog.restoreState();
14890  </code></pre>
14891  * @singleton
14892  */
14893 Roo.state.Manager = function(){
14894     var provider = new Roo.state.Provider();
14895     
14896     return {
14897         /**
14898          * Configures the default state provider for your application
14899          * @param {Provider} stateProvider The state provider to set
14900          */
14901         setProvider : function(stateProvider){
14902             provider = stateProvider;
14903         },
14904         
14905         /**
14906          * Returns the current value for a key
14907          * @param {String} name The key name
14908          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14909          * @return {Mixed} The state data
14910          */
14911         get : function(key, defaultValue){
14912             return provider.get(key, defaultValue);
14913         },
14914         
14915         /**
14916          * Sets the value for a key
14917          * @param {String} name The key name
14918          * @param {Mixed} value The state data
14919          */
14920          set : function(key, value){
14921             provider.set(key, value);
14922         },
14923         
14924         /**
14925          * Clears a value from the state
14926          * @param {String} name The key name
14927          */
14928         clear : function(key){
14929             provider.clear(key);
14930         },
14931         
14932         /**
14933          * Gets the currently configured state provider
14934          * @return {Provider} The state provider
14935          */
14936         getProvider : function(){
14937             return provider;
14938         }
14939     };
14940 }();
14941 /*
14942  * Based on:
14943  * Ext JS Library 1.1.1
14944  * Copyright(c) 2006-2007, Ext JS, LLC.
14945  *
14946  * Originally Released Under LGPL - original licence link has changed is not relivant.
14947  *
14948  * Fork - LGPL
14949  * <script type="text/javascript">
14950  */
14951 /**
14952  * @class Roo.state.CookieProvider
14953  * @extends Roo.state.Provider
14954  * The default Provider implementation which saves state via cookies.
14955  * <br />Usage:
14956  <pre><code>
14957    var cp = new Roo.state.CookieProvider({
14958        path: "/cgi-bin/",
14959        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14960        domain: "roojs.com"
14961    })
14962    Roo.state.Manager.setProvider(cp);
14963  </code></pre>
14964  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14965  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14966  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14967  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14968  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14969  * domain the page is running on including the 'www' like 'www.roojs.com')
14970  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14971  * @constructor
14972  * Create a new CookieProvider
14973  * @param {Object} config The configuration object
14974  */
14975 Roo.state.CookieProvider = function(config){
14976     Roo.state.CookieProvider.superclass.constructor.call(this);
14977     this.path = "/";
14978     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14979     this.domain = null;
14980     this.secure = false;
14981     Roo.apply(this, config);
14982     this.state = this.readCookies();
14983 };
14984
14985 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14986     // private
14987     set : function(name, value){
14988         if(typeof value == "undefined" || value === null){
14989             this.clear(name);
14990             return;
14991         }
14992         this.setCookie(name, value);
14993         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14994     },
14995
14996     // private
14997     clear : function(name){
14998         this.clearCookie(name);
14999         Roo.state.CookieProvider.superclass.clear.call(this, name);
15000     },
15001
15002     // private
15003     readCookies : function(){
15004         var cookies = {};
15005         var c = document.cookie + ";";
15006         var re = /\s?(.*?)=(.*?);/g;
15007         var matches;
15008         while((matches = re.exec(c)) != null){
15009             var name = matches[1];
15010             var value = matches[2];
15011             if(name && name.substring(0,3) == "ys-"){
15012                 cookies[name.substr(3)] = this.decodeValue(value);
15013             }
15014         }
15015         return cookies;
15016     },
15017
15018     // private
15019     setCookie : function(name, value){
15020         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15021            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15022            ((this.path == null) ? "" : ("; path=" + this.path)) +
15023            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15024            ((this.secure == true) ? "; secure" : "");
15025     },
15026
15027     // private
15028     clearCookie : function(name){
15029         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15030            ((this.path == null) ? "" : ("; path=" + this.path)) +
15031            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15032            ((this.secure == true) ? "; secure" : "");
15033     }
15034 });/*
15035  * Based on:
15036  * Ext JS Library 1.1.1
15037  * Copyright(c) 2006-2007, Ext JS, LLC.
15038  *
15039  * Originally Released Under LGPL - original licence link has changed is not relivant.
15040  *
15041  * Fork - LGPL
15042  * <script type="text/javascript">
15043  */
15044  
15045
15046 /**
15047  * @class Roo.ComponentMgr
15048  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15049  * @singleton
15050  */
15051 Roo.ComponentMgr = function(){
15052     var all = new Roo.util.MixedCollection();
15053
15054     return {
15055         /**
15056          * Registers a component.
15057          * @param {Roo.Component} c The component
15058          */
15059         register : function(c){
15060             all.add(c);
15061         },
15062
15063         /**
15064          * Unregisters a component.
15065          * @param {Roo.Component} c The component
15066          */
15067         unregister : function(c){
15068             all.remove(c);
15069         },
15070
15071         /**
15072          * Returns a component by id
15073          * @param {String} id The component id
15074          */
15075         get : function(id){
15076             return all.get(id);
15077         },
15078
15079         /**
15080          * Registers a function that will be called when a specified component is added to ComponentMgr
15081          * @param {String} id The component id
15082          * @param {Funtction} fn The callback function
15083          * @param {Object} scope The scope of the callback
15084          */
15085         onAvailable : function(id, fn, scope){
15086             all.on("add", function(index, o){
15087                 if(o.id == id){
15088                     fn.call(scope || o, o);
15089                     all.un("add", fn, scope);
15090                 }
15091             });
15092         }
15093     };
15094 }();/*
15095  * Based on:
15096  * Ext JS Library 1.1.1
15097  * Copyright(c) 2006-2007, Ext JS, LLC.
15098  *
15099  * Originally Released Under LGPL - original licence link has changed is not relivant.
15100  *
15101  * Fork - LGPL
15102  * <script type="text/javascript">
15103  */
15104  
15105 /**
15106  * @class Roo.Component
15107  * @extends Roo.util.Observable
15108  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15109  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15110  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15111  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15112  * All visual components (widgets) that require rendering into a layout should subclass Component.
15113  * @constructor
15114  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15115  * 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
15116  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15117  */
15118 Roo.Component = function(config){
15119     config = config || {};
15120     if(config.tagName || config.dom || typeof config == "string"){ // element object
15121         config = {el: config, id: config.id || config};
15122     }
15123     this.initialConfig = config;
15124
15125     Roo.apply(this, config);
15126     this.addEvents({
15127         /**
15128          * @event disable
15129          * Fires after the component is disabled.
15130              * @param {Roo.Component} this
15131              */
15132         disable : true,
15133         /**
15134          * @event enable
15135          * Fires after the component is enabled.
15136              * @param {Roo.Component} this
15137              */
15138         enable : true,
15139         /**
15140          * @event beforeshow
15141          * Fires before the component is shown.  Return false to stop the show.
15142              * @param {Roo.Component} this
15143              */
15144         beforeshow : true,
15145         /**
15146          * @event show
15147          * Fires after the component is shown.
15148              * @param {Roo.Component} this
15149              */
15150         show : true,
15151         /**
15152          * @event beforehide
15153          * Fires before the component is hidden. Return false to stop the hide.
15154              * @param {Roo.Component} this
15155              */
15156         beforehide : true,
15157         /**
15158          * @event hide
15159          * Fires after the component is hidden.
15160              * @param {Roo.Component} this
15161              */
15162         hide : true,
15163         /**
15164          * @event beforerender
15165          * Fires before the component is rendered. Return false to stop the render.
15166              * @param {Roo.Component} this
15167              */
15168         beforerender : true,
15169         /**
15170          * @event render
15171          * Fires after the component is rendered.
15172              * @param {Roo.Component} this
15173              */
15174         render : true,
15175         /**
15176          * @event beforedestroy
15177          * Fires before the component is destroyed. Return false to stop the destroy.
15178              * @param {Roo.Component} this
15179              */
15180         beforedestroy : true,
15181         /**
15182          * @event destroy
15183          * Fires after the component is destroyed.
15184              * @param {Roo.Component} this
15185              */
15186         destroy : true
15187     });
15188     if(!this.id){
15189         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15190     }
15191     Roo.ComponentMgr.register(this);
15192     Roo.Component.superclass.constructor.call(this);
15193     this.initComponent();
15194     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15195         this.render(this.renderTo);
15196         delete this.renderTo;
15197     }
15198 };
15199
15200 /** @private */
15201 Roo.Component.AUTO_ID = 1000;
15202
15203 Roo.extend(Roo.Component, Roo.util.Observable, {
15204     /**
15205      * @scope Roo.Component.prototype
15206      * @type {Boolean}
15207      * true if this component is hidden. Read-only.
15208      */
15209     hidden : false,
15210     /**
15211      * @type {Boolean}
15212      * true if this component is disabled. Read-only.
15213      */
15214     disabled : false,
15215     /**
15216      * @type {Boolean}
15217      * true if this component has been rendered. Read-only.
15218      */
15219     rendered : false,
15220     
15221     /** @cfg {String} disableClass
15222      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15223      */
15224     disabledClass : "x-item-disabled",
15225         /** @cfg {Boolean} allowDomMove
15226          * Whether the component can move the Dom node when rendering (defaults to true).
15227          */
15228     allowDomMove : true,
15229     /** @cfg {String} hideMode (display|visibility)
15230      * How this component should hidden. Supported values are
15231      * "visibility" (css visibility), "offsets" (negative offset position) and
15232      * "display" (css display) - defaults to "display".
15233      */
15234     hideMode: 'display',
15235
15236     /** @private */
15237     ctype : "Roo.Component",
15238
15239     /**
15240      * @cfg {String} actionMode 
15241      * which property holds the element that used for  hide() / show() / disable() / enable()
15242      * default is 'el' 
15243      */
15244     actionMode : "el",
15245
15246     /** @private */
15247     getActionEl : function(){
15248         return this[this.actionMode];
15249     },
15250
15251     initComponent : Roo.emptyFn,
15252     /**
15253      * If this is a lazy rendering component, render it to its container element.
15254      * @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.
15255      */
15256     render : function(container, position){
15257         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15258             if(!container && this.el){
15259                 this.el = Roo.get(this.el);
15260                 container = this.el.dom.parentNode;
15261                 this.allowDomMove = false;
15262             }
15263             this.container = Roo.get(container);
15264             this.rendered = true;
15265             if(position !== undefined){
15266                 if(typeof position == 'number'){
15267                     position = this.container.dom.childNodes[position];
15268                 }else{
15269                     position = Roo.getDom(position);
15270                 }
15271             }
15272             this.onRender(this.container, position || null);
15273             if(this.cls){
15274                 this.el.addClass(this.cls);
15275                 delete this.cls;
15276             }
15277             if(this.style){
15278                 this.el.applyStyles(this.style);
15279                 delete this.style;
15280             }
15281             this.fireEvent("render", this);
15282             this.afterRender(this.container);
15283             if(this.hidden){
15284                 this.hide();
15285             }
15286             if(this.disabled){
15287                 this.disable();
15288             }
15289         }
15290         return this;
15291     },
15292
15293     /** @private */
15294     // default function is not really useful
15295     onRender : function(ct, position){
15296         if(this.el){
15297             this.el = Roo.get(this.el);
15298             if(this.allowDomMove !== false){
15299                 ct.dom.insertBefore(this.el.dom, position);
15300             }
15301         }
15302     },
15303
15304     /** @private */
15305     getAutoCreate : function(){
15306         var cfg = typeof this.autoCreate == "object" ?
15307                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15308         if(this.id && !cfg.id){
15309             cfg.id = this.id;
15310         }
15311         return cfg;
15312     },
15313
15314     /** @private */
15315     afterRender : Roo.emptyFn,
15316
15317     /**
15318      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15319      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15320      */
15321     destroy : function(){
15322         if(this.fireEvent("beforedestroy", this) !== false){
15323             this.purgeListeners();
15324             this.beforeDestroy();
15325             if(this.rendered){
15326                 this.el.removeAllListeners();
15327                 this.el.remove();
15328                 if(this.actionMode == "container"){
15329                     this.container.remove();
15330                 }
15331             }
15332             this.onDestroy();
15333             Roo.ComponentMgr.unregister(this);
15334             this.fireEvent("destroy", this);
15335         }
15336     },
15337
15338         /** @private */
15339     beforeDestroy : function(){
15340
15341     },
15342
15343         /** @private */
15344         onDestroy : function(){
15345
15346     },
15347
15348     /**
15349      * Returns the underlying {@link Roo.Element}.
15350      * @return {Roo.Element} The element
15351      */
15352     getEl : function(){
15353         return this.el;
15354     },
15355
15356     /**
15357      * Returns the id of this component.
15358      * @return {String}
15359      */
15360     getId : function(){
15361         return this.id;
15362     },
15363
15364     /**
15365      * Try to focus this component.
15366      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15367      * @return {Roo.Component} this
15368      */
15369     focus : function(selectText){
15370         if(this.rendered){
15371             this.el.focus();
15372             if(selectText === true){
15373                 this.el.dom.select();
15374             }
15375         }
15376         return this;
15377     },
15378
15379     /** @private */
15380     blur : function(){
15381         if(this.rendered){
15382             this.el.blur();
15383         }
15384         return this;
15385     },
15386
15387     /**
15388      * Disable this component.
15389      * @return {Roo.Component} this
15390      */
15391     disable : function(){
15392         if(this.rendered){
15393             this.onDisable();
15394         }
15395         this.disabled = true;
15396         this.fireEvent("disable", this);
15397         return this;
15398     },
15399
15400         // private
15401     onDisable : function(){
15402         this.getActionEl().addClass(this.disabledClass);
15403         this.el.dom.disabled = true;
15404     },
15405
15406     /**
15407      * Enable this component.
15408      * @return {Roo.Component} this
15409      */
15410     enable : function(){
15411         if(this.rendered){
15412             this.onEnable();
15413         }
15414         this.disabled = false;
15415         this.fireEvent("enable", this);
15416         return this;
15417     },
15418
15419         // private
15420     onEnable : function(){
15421         this.getActionEl().removeClass(this.disabledClass);
15422         this.el.dom.disabled = false;
15423     },
15424
15425     /**
15426      * Convenience function for setting disabled/enabled by boolean.
15427      * @param {Boolean} disabled
15428      */
15429     setDisabled : function(disabled){
15430         this[disabled ? "disable" : "enable"]();
15431     },
15432
15433     /**
15434      * Show this component.
15435      * @return {Roo.Component} this
15436      */
15437     show: function(){
15438         if(this.fireEvent("beforeshow", this) !== false){
15439             this.hidden = false;
15440             if(this.rendered){
15441                 this.onShow();
15442             }
15443             this.fireEvent("show", this);
15444         }
15445         return this;
15446     },
15447
15448     // private
15449     onShow : function(){
15450         var ae = this.getActionEl();
15451         if(this.hideMode == 'visibility'){
15452             ae.dom.style.visibility = "visible";
15453         }else if(this.hideMode == 'offsets'){
15454             ae.removeClass('x-hidden');
15455         }else{
15456             ae.dom.style.display = "";
15457         }
15458     },
15459
15460     /**
15461      * Hide this component.
15462      * @return {Roo.Component} this
15463      */
15464     hide: function(){
15465         if(this.fireEvent("beforehide", this) !== false){
15466             this.hidden = true;
15467             if(this.rendered){
15468                 this.onHide();
15469             }
15470             this.fireEvent("hide", this);
15471         }
15472         return this;
15473     },
15474
15475     // private
15476     onHide : function(){
15477         var ae = this.getActionEl();
15478         if(this.hideMode == 'visibility'){
15479             ae.dom.style.visibility = "hidden";
15480         }else if(this.hideMode == 'offsets'){
15481             ae.addClass('x-hidden');
15482         }else{
15483             ae.dom.style.display = "none";
15484         }
15485     },
15486
15487     /**
15488      * Convenience function to hide or show this component by boolean.
15489      * @param {Boolean} visible True to show, false to hide
15490      * @return {Roo.Component} this
15491      */
15492     setVisible: function(visible){
15493         if(visible) {
15494             this.show();
15495         }else{
15496             this.hide();
15497         }
15498         return this;
15499     },
15500
15501     /**
15502      * Returns true if this component is visible.
15503      */
15504     isVisible : function(){
15505         return this.getActionEl().isVisible();
15506     },
15507
15508     cloneConfig : function(overrides){
15509         overrides = overrides || {};
15510         var id = overrides.id || Roo.id();
15511         var cfg = Roo.applyIf(overrides, this.initialConfig);
15512         cfg.id = id; // prevent dup id
15513         return new this.constructor(cfg);
15514     }
15515 });/*
15516  * Based on:
15517  * Ext JS Library 1.1.1
15518  * Copyright(c) 2006-2007, Ext JS, LLC.
15519  *
15520  * Originally Released Under LGPL - original licence link has changed is not relivant.
15521  *
15522  * Fork - LGPL
15523  * <script type="text/javascript">
15524  */
15525
15526 /**
15527  * @class Roo.BoxComponent
15528  * @extends Roo.Component
15529  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15530  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15531  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15532  * layout containers.
15533  * @constructor
15534  * @param {Roo.Element/String/Object} config The configuration options.
15535  */
15536 Roo.BoxComponent = function(config){
15537     Roo.Component.call(this, config);
15538     this.addEvents({
15539         /**
15540          * @event resize
15541          * Fires after the component is resized.
15542              * @param {Roo.Component} this
15543              * @param {Number} adjWidth The box-adjusted width that was set
15544              * @param {Number} adjHeight The box-adjusted height that was set
15545              * @param {Number} rawWidth The width that was originally specified
15546              * @param {Number} rawHeight The height that was originally specified
15547              */
15548         resize : true,
15549         /**
15550          * @event move
15551          * Fires after the component is moved.
15552              * @param {Roo.Component} this
15553              * @param {Number} x The new x position
15554              * @param {Number} y The new y position
15555              */
15556         move : true
15557     });
15558 };
15559
15560 Roo.extend(Roo.BoxComponent, Roo.Component, {
15561     // private, set in afterRender to signify that the component has been rendered
15562     boxReady : false,
15563     // private, used to defer height settings to subclasses
15564     deferHeight: false,
15565     /** @cfg {Number} width
15566      * width (optional) size of component
15567      */
15568      /** @cfg {Number} height
15569      * height (optional) size of component
15570      */
15571      
15572     /**
15573      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15574      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15575      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15576      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15577      * @return {Roo.BoxComponent} this
15578      */
15579     setSize : function(w, h){
15580         // support for standard size objects
15581         if(typeof w == 'object'){
15582             h = w.height;
15583             w = w.width;
15584         }
15585         // not rendered
15586         if(!this.boxReady){
15587             this.width = w;
15588             this.height = h;
15589             return this;
15590         }
15591
15592         // prevent recalcs when not needed
15593         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15594             return this;
15595         }
15596         this.lastSize = {width: w, height: h};
15597
15598         var adj = this.adjustSize(w, h);
15599         var aw = adj.width, ah = adj.height;
15600         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15601             var rz = this.getResizeEl();
15602             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15603                 rz.setSize(aw, ah);
15604             }else if(!this.deferHeight && ah !== undefined){
15605                 rz.setHeight(ah);
15606             }else if(aw !== undefined){
15607                 rz.setWidth(aw);
15608             }
15609             this.onResize(aw, ah, w, h);
15610             this.fireEvent('resize', this, aw, ah, w, h);
15611         }
15612         return this;
15613     },
15614
15615     /**
15616      * Gets the current size of the component's underlying element.
15617      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15618      */
15619     getSize : function(){
15620         return this.el.getSize();
15621     },
15622
15623     /**
15624      * Gets the current XY position of the component's underlying element.
15625      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15626      * @return {Array} The XY position of the element (e.g., [100, 200])
15627      */
15628     getPosition : function(local){
15629         if(local === true){
15630             return [this.el.getLeft(true), this.el.getTop(true)];
15631         }
15632         return this.xy || this.el.getXY();
15633     },
15634
15635     /**
15636      * Gets the current box measurements of the component's underlying element.
15637      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15638      * @returns {Object} box An object in the format {x, y, width, height}
15639      */
15640     getBox : function(local){
15641         var s = this.el.getSize();
15642         if(local){
15643             s.x = this.el.getLeft(true);
15644             s.y = this.el.getTop(true);
15645         }else{
15646             var xy = this.xy || this.el.getXY();
15647             s.x = xy[0];
15648             s.y = xy[1];
15649         }
15650         return s;
15651     },
15652
15653     /**
15654      * Sets the current box measurements of the component's underlying element.
15655      * @param {Object} box An object in the format {x, y, width, height}
15656      * @returns {Roo.BoxComponent} this
15657      */
15658     updateBox : function(box){
15659         this.setSize(box.width, box.height);
15660         this.setPagePosition(box.x, box.y);
15661         return this;
15662     },
15663
15664     // protected
15665     getResizeEl : function(){
15666         return this.resizeEl || this.el;
15667     },
15668
15669     // protected
15670     getPositionEl : function(){
15671         return this.positionEl || this.el;
15672     },
15673
15674     /**
15675      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15676      * This method fires the move event.
15677      * @param {Number} left The new left
15678      * @param {Number} top The new top
15679      * @returns {Roo.BoxComponent} this
15680      */
15681     setPosition : function(x, y){
15682         this.x = x;
15683         this.y = y;
15684         if(!this.boxReady){
15685             return this;
15686         }
15687         var adj = this.adjustPosition(x, y);
15688         var ax = adj.x, ay = adj.y;
15689
15690         var el = this.getPositionEl();
15691         if(ax !== undefined || ay !== undefined){
15692             if(ax !== undefined && ay !== undefined){
15693                 el.setLeftTop(ax, ay);
15694             }else if(ax !== undefined){
15695                 el.setLeft(ax);
15696             }else if(ay !== undefined){
15697                 el.setTop(ay);
15698             }
15699             this.onPosition(ax, ay);
15700             this.fireEvent('move', this, ax, ay);
15701         }
15702         return this;
15703     },
15704
15705     /**
15706      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15707      * This method fires the move event.
15708      * @param {Number} x The new x position
15709      * @param {Number} y The new y position
15710      * @returns {Roo.BoxComponent} this
15711      */
15712     setPagePosition : function(x, y){
15713         this.pageX = x;
15714         this.pageY = y;
15715         if(!this.boxReady){
15716             return;
15717         }
15718         if(x === undefined || y === undefined){ // cannot translate undefined points
15719             return;
15720         }
15721         var p = this.el.translatePoints(x, y);
15722         this.setPosition(p.left, p.top);
15723         return this;
15724     },
15725
15726     // private
15727     onRender : function(ct, position){
15728         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15729         if(this.resizeEl){
15730             this.resizeEl = Roo.get(this.resizeEl);
15731         }
15732         if(this.positionEl){
15733             this.positionEl = Roo.get(this.positionEl);
15734         }
15735     },
15736
15737     // private
15738     afterRender : function(){
15739         Roo.BoxComponent.superclass.afterRender.call(this);
15740         this.boxReady = true;
15741         this.setSize(this.width, this.height);
15742         if(this.x || this.y){
15743             this.setPosition(this.x, this.y);
15744         }
15745         if(this.pageX || this.pageY){
15746             this.setPagePosition(this.pageX, this.pageY);
15747         }
15748     },
15749
15750     /**
15751      * Force the component's size to recalculate based on the underlying element's current height and width.
15752      * @returns {Roo.BoxComponent} this
15753      */
15754     syncSize : function(){
15755         delete this.lastSize;
15756         this.setSize(this.el.getWidth(), this.el.getHeight());
15757         return this;
15758     },
15759
15760     /**
15761      * Called after the component is resized, this method is empty by default but can be implemented by any
15762      * subclass that needs to perform custom logic after a resize occurs.
15763      * @param {Number} adjWidth The box-adjusted width that was set
15764      * @param {Number} adjHeight The box-adjusted height that was set
15765      * @param {Number} rawWidth The width that was originally specified
15766      * @param {Number} rawHeight The height that was originally specified
15767      */
15768     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15769
15770     },
15771
15772     /**
15773      * Called after the component is moved, this method is empty by default but can be implemented by any
15774      * subclass that needs to perform custom logic after a move occurs.
15775      * @param {Number} x The new x position
15776      * @param {Number} y The new y position
15777      */
15778     onPosition : function(x, y){
15779
15780     },
15781
15782     // private
15783     adjustSize : function(w, h){
15784         if(this.autoWidth){
15785             w = 'auto';
15786         }
15787         if(this.autoHeight){
15788             h = 'auto';
15789         }
15790         return {width : w, height: h};
15791     },
15792
15793     // private
15794     adjustPosition : function(x, y){
15795         return {x : x, y: y};
15796     }
15797 });/*
15798  * Original code for Roojs - LGPL
15799  * <script type="text/javascript">
15800  */
15801  
15802 /**
15803  * @class Roo.XComponent
15804  * A delayed Element creator...
15805  * Or a way to group chunks of interface together.
15806  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15807  *  used in conjunction with XComponent.build() it will create an instance of each element,
15808  *  then call addxtype() to build the User interface.
15809  * 
15810  * Mypart.xyx = new Roo.XComponent({
15811
15812     parent : 'Mypart.xyz', // empty == document.element.!!
15813     order : '001',
15814     name : 'xxxx'
15815     region : 'xxxx'
15816     disabled : function() {} 
15817      
15818     tree : function() { // return an tree of xtype declared components
15819         var MODULE = this;
15820         return 
15821         {
15822             xtype : 'NestedLayoutPanel',
15823             // technicall
15824         }
15825      ]
15826  *})
15827  *
15828  *
15829  * It can be used to build a big heiracy, with parent etc.
15830  * or you can just use this to render a single compoent to a dom element
15831  * MYPART.render(Roo.Element | String(id) | dom_element )
15832  *
15833  *
15834  * Usage patterns.
15835  *
15836  * Classic Roo
15837  *
15838  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15839  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15840  *
15841  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15842  *
15843  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15844  * - if mulitple topModules exist, the last one is defined as the top module.
15845  *
15846  * Embeded Roo
15847  * 
15848  * When the top level or multiple modules are to embedded into a existing HTML page,
15849  * the parent element can container '#id' of the element where the module will be drawn.
15850  *
15851  * Bootstrap Roo
15852  *
15853  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15854  * it relies more on a include mechanism, where sub modules are included into an outer page.
15855  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15856  * 
15857  * Bootstrap Roo Included elements
15858  *
15859  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15860  * hence confusing the component builder as it thinks there are multiple top level elements. 
15861  *
15862  * 
15863  * 
15864  * @extends Roo.util.Observable
15865  * @constructor
15866  * @param cfg {Object} configuration of component
15867  * 
15868  */
15869 Roo.XComponent = function(cfg) {
15870     Roo.apply(this, cfg);
15871     this.addEvents({ 
15872         /**
15873              * @event built
15874              * Fires when this the componnt is built
15875              * @param {Roo.XComponent} c the component
15876              */
15877         'built' : true
15878         
15879     });
15880     this.region = this.region || 'center'; // default..
15881     Roo.XComponent.register(this);
15882     this.modules = false;
15883     this.el = false; // where the layout goes..
15884     
15885     
15886 }
15887 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15888     /**
15889      * @property el
15890      * The created element (with Roo.factory())
15891      * @type {Roo.Layout}
15892      */
15893     el  : false,
15894     
15895     /**
15896      * @property el
15897      * for BC  - use el in new code
15898      * @type {Roo.Layout}
15899      */
15900     panel : false,
15901     
15902     /**
15903      * @property layout
15904      * for BC  - use el in new code
15905      * @type {Roo.Layout}
15906      */
15907     layout : false,
15908     
15909      /**
15910      * @cfg {Function|boolean} disabled
15911      * If this module is disabled by some rule, return true from the funtion
15912      */
15913     disabled : false,
15914     
15915     /**
15916      * @cfg {String} parent 
15917      * Name of parent element which it get xtype added to..
15918      */
15919     parent: false,
15920     
15921     /**
15922      * @cfg {String} order
15923      * Used to set the order in which elements are created (usefull for multiple tabs)
15924      */
15925     
15926     order : false,
15927     /**
15928      * @cfg {String} name
15929      * String to display while loading.
15930      */
15931     name : false,
15932     /**
15933      * @cfg {String} region
15934      * Region to render component to (defaults to center)
15935      */
15936     region : 'center',
15937     
15938     /**
15939      * @cfg {Array} items
15940      * A single item array - the first element is the root of the tree..
15941      * It's done this way to stay compatible with the Xtype system...
15942      */
15943     items : false,
15944     
15945     /**
15946      * @property _tree
15947      * The method that retuns the tree of parts that make up this compoennt 
15948      * @type {function}
15949      */
15950     _tree  : false,
15951     
15952      /**
15953      * render
15954      * render element to dom or tree
15955      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15956      */
15957     
15958     render : function(el)
15959     {
15960         
15961         el = el || false;
15962         var hp = this.parent ? 1 : 0;
15963         Roo.debug &&  Roo.log(this);
15964         
15965         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15966             // if parent is a '#.....' string, then let's use that..
15967             var ename = this.parent.substr(1);
15968             this.parent = false;
15969             Roo.debug && Roo.log(ename);
15970             switch (ename) {
15971                 case 'bootstrap-body' :
15972                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15973                         this.parent = { el :  new  Roo.bootstrap.Body() };
15974                         Roo.debug && Roo.log("setting el to doc body");
15975                          
15976                     } else {
15977                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15978                     }
15979                     break;
15980                 case 'bootstrap':
15981                     this.parent = { el : true};
15982                     // fall through
15983                 default:
15984                     el = Roo.get(ename);
15985                     break;
15986             }
15987                 
15988             
15989             if (!el && !this.parent) {
15990                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15991                 return;
15992             }
15993         }
15994         Roo.debug && Roo.log("EL:");
15995         Roo.debug && Roo.log(el);
15996         Roo.debug && Roo.log("this.parent.el:");
15997         Roo.debug && Roo.log(this.parent.el);
15998         
15999         var tree = this._tree ? this._tree() : this.tree();
16000
16001         // altertive root elements ??? - we need a better way to indicate these.
16002         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16003                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16004         
16005         if (!this.parent && is_alt) {
16006             //el = Roo.get(document.body);
16007             this.parent = { el : true };
16008         }
16009             
16010             
16011         
16012         if (!this.parent) {
16013             
16014             Roo.debug && Roo.log("no parent - creating one");
16015             
16016             el = el ? Roo.get(el) : false;      
16017             
16018             // it's a top level one..
16019             this.parent =  {
16020                 el : new Roo.BorderLayout(el || document.body, {
16021                 
16022                      center: {
16023                          titlebar: false,
16024                          autoScroll:false,
16025                          closeOnTab: true,
16026                          tabPosition: 'top',
16027                           //resizeTabs: true,
16028                          alwaysShowTabs: el && hp? false :  true,
16029                          hideTabs: el || !hp ? true :  false,
16030                          minTabWidth: 140
16031                      }
16032                  })
16033             }
16034         }
16035         
16036         if (!this.parent.el) {
16037                 // probably an old style ctor, which has been disabled.
16038                 return;
16039
16040         }
16041                 // The 'tree' method is  '_tree now' 
16042             
16043         tree.region = tree.region || this.region;
16044         
16045         if (this.parent.el === true) {
16046             // bootstrap... - body..
16047             this.parent.el = Roo.factory(tree);
16048         }
16049         
16050         this.el = this.parent.el.addxtype(tree);
16051         this.fireEvent('built', this);
16052         
16053         this.panel = this.el;
16054         this.layout = this.panel.layout;
16055         this.parentLayout = this.parent.layout  || false;  
16056          
16057     }
16058     
16059 });
16060
16061 Roo.apply(Roo.XComponent, {
16062     /**
16063      * @property  hideProgress
16064      * true to disable the building progress bar.. usefull on single page renders.
16065      * @type Boolean
16066      */
16067     hideProgress : false,
16068     /**
16069      * @property  buildCompleted
16070      * True when the builder has completed building the interface.
16071      * @type Boolean
16072      */
16073     buildCompleted : false,
16074      
16075     /**
16076      * @property  topModule
16077      * the upper most module - uses document.element as it's constructor.
16078      * @type Object
16079      */
16080      
16081     topModule  : false,
16082       
16083     /**
16084      * @property  modules
16085      * array of modules to be created by registration system.
16086      * @type {Array} of Roo.XComponent
16087      */
16088     
16089     modules : [],
16090     /**
16091      * @property  elmodules
16092      * array of modules to be created by which use #ID 
16093      * @type {Array} of Roo.XComponent
16094      */
16095      
16096     elmodules : [],
16097
16098      /**
16099      * @property  build_from_html
16100      * Build elements from html - used by bootstrap HTML stuff 
16101      *    - this is cleared after build is completed
16102      * @type {boolean} true  (default false)
16103      */
16104      
16105     build_from_html : false,
16106
16107     /**
16108      * Register components to be built later.
16109      *
16110      * This solves the following issues
16111      * - Building is not done on page load, but after an authentication process has occured.
16112      * - Interface elements are registered on page load
16113      * - Parent Interface elements may not be loaded before child, so this handles that..
16114      * 
16115      *
16116      * example:
16117      * 
16118      * MyApp.register({
16119           order : '000001',
16120           module : 'Pman.Tab.projectMgr',
16121           region : 'center',
16122           parent : 'Pman.layout',
16123           disabled : false,  // or use a function..
16124         })
16125      
16126      * * @param {Object} details about module
16127      */
16128     register : function(obj) {
16129                 
16130         Roo.XComponent.event.fireEvent('register', obj);
16131         switch(typeof(obj.disabled) ) {
16132                 
16133             case 'undefined':
16134                 break;
16135             
16136             case 'function':
16137                 if ( obj.disabled() ) {
16138                         return;
16139                 }
16140                 break;
16141             
16142             default:
16143                 if (obj.disabled) {
16144                         return;
16145                 }
16146                 break;
16147         }
16148                 
16149         this.modules.push(obj);
16150          
16151     },
16152     /**
16153      * convert a string to an object..
16154      * eg. 'AAA.BBB' -> finds AAA.BBB
16155
16156      */
16157     
16158     toObject : function(str)
16159     {
16160         if (!str || typeof(str) == 'object') {
16161             return str;
16162         }
16163         if (str.substring(0,1) == '#') {
16164             return str;
16165         }
16166
16167         var ar = str.split('.');
16168         var rt, o;
16169         rt = ar.shift();
16170             /** eval:var:o */
16171         try {
16172             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16173         } catch (e) {
16174             throw "Module not found : " + str;
16175         }
16176         
16177         if (o === false) {
16178             throw "Module not found : " + str;
16179         }
16180         Roo.each(ar, function(e) {
16181             if (typeof(o[e]) == 'undefined') {
16182                 throw "Module not found : " + str;
16183             }
16184             o = o[e];
16185         });
16186         
16187         return o;
16188         
16189     },
16190     
16191     
16192     /**
16193      * move modules into their correct place in the tree..
16194      * 
16195      */
16196     preBuild : function ()
16197     {
16198         var _t = this;
16199         Roo.each(this.modules , function (obj)
16200         {
16201             Roo.XComponent.event.fireEvent('beforebuild', obj);
16202             
16203             var opar = obj.parent;
16204             try { 
16205                 obj.parent = this.toObject(opar);
16206             } catch(e) {
16207                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16208                 return;
16209             }
16210             
16211             if (!obj.parent) {
16212                 Roo.debug && Roo.log("GOT top level module");
16213                 Roo.debug && Roo.log(obj);
16214                 obj.modules = new Roo.util.MixedCollection(false, 
16215                     function(o) { return o.order + '' }
16216                 );
16217                 this.topModule = obj;
16218                 return;
16219             }
16220                         // parent is a string (usually a dom element name..)
16221             if (typeof(obj.parent) == 'string') {
16222                 this.elmodules.push(obj);
16223                 return;
16224             }
16225             if (obj.parent.constructor != Roo.XComponent) {
16226                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16227             }
16228             if (!obj.parent.modules) {
16229                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16230                     function(o) { return o.order + '' }
16231                 );
16232             }
16233             if (obj.parent.disabled) {
16234                 obj.disabled = true;
16235             }
16236             obj.parent.modules.add(obj);
16237         }, this);
16238     },
16239     
16240      /**
16241      * make a list of modules to build.
16242      * @return {Array} list of modules. 
16243      */ 
16244     
16245     buildOrder : function()
16246     {
16247         var _this = this;
16248         var cmp = function(a,b) {   
16249             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16250         };
16251         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16252             throw "No top level modules to build";
16253         }
16254         
16255         // make a flat list in order of modules to build.
16256         var mods = this.topModule ? [ this.topModule ] : [];
16257                 
16258         
16259         // elmodules (is a list of DOM based modules )
16260         Roo.each(this.elmodules, function(e) {
16261             mods.push(e);
16262             if (!this.topModule &&
16263                 typeof(e.parent) == 'string' &&
16264                 e.parent.substring(0,1) == '#' &&
16265                 Roo.get(e.parent.substr(1))
16266                ) {
16267                 
16268                 _this.topModule = e;
16269             }
16270             
16271         });
16272
16273         
16274         // add modules to their parents..
16275         var addMod = function(m) {
16276             Roo.debug && Roo.log("build Order: add: " + m.name);
16277                 
16278             mods.push(m);
16279             if (m.modules && !m.disabled) {
16280                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16281                 m.modules.keySort('ASC',  cmp );
16282                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16283     
16284                 m.modules.each(addMod);
16285             } else {
16286                 Roo.debug && Roo.log("build Order: no child modules");
16287             }
16288             // not sure if this is used any more..
16289             if (m.finalize) {
16290                 m.finalize.name = m.name + " (clean up) ";
16291                 mods.push(m.finalize);
16292             }
16293             
16294         }
16295         if (this.topModule && this.topModule.modules) { 
16296             this.topModule.modules.keySort('ASC',  cmp );
16297             this.topModule.modules.each(addMod);
16298         } 
16299         return mods;
16300     },
16301     
16302      /**
16303      * Build the registered modules.
16304      * @param {Object} parent element.
16305      * @param {Function} optional method to call after module has been added.
16306      * 
16307      */ 
16308    
16309     build : function(opts) 
16310     {
16311         
16312         if (typeof(opts) != 'undefined') {
16313             Roo.apply(this,opts);
16314         }
16315         
16316         this.preBuild();
16317         var mods = this.buildOrder();
16318       
16319         //this.allmods = mods;
16320         //Roo.debug && Roo.log(mods);
16321         //return;
16322         if (!mods.length) { // should not happen
16323             throw "NO modules!!!";
16324         }
16325         
16326         
16327         var msg = "Building Interface...";
16328         // flash it up as modal - so we store the mask!?
16329         if (!this.hideProgress && Roo.MessageBox) {
16330             Roo.MessageBox.show({ title: 'loading' });
16331             Roo.MessageBox.show({
16332                title: "Please wait...",
16333                msg: msg,
16334                width:450,
16335                progress:true,
16336                closable:false,
16337                modal: false
16338               
16339             });
16340         }
16341         var total = mods.length;
16342         
16343         var _this = this;
16344         var progressRun = function() {
16345             if (!mods.length) {
16346                 Roo.debug && Roo.log('hide?');
16347                 if (!this.hideProgress && Roo.MessageBox) {
16348                     Roo.MessageBox.hide();
16349                 }
16350                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16351                 
16352                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16353                 
16354                 // THE END...
16355                 return false;   
16356             }
16357             
16358             var m = mods.shift();
16359             
16360             
16361             Roo.debug && Roo.log(m);
16362             // not sure if this is supported any more.. - modules that are are just function
16363             if (typeof(m) == 'function') { 
16364                 m.call(this);
16365                 return progressRun.defer(10, _this);
16366             } 
16367             
16368             
16369             msg = "Building Interface " + (total  - mods.length) + 
16370                     " of " + total + 
16371                     (m.name ? (' - ' + m.name) : '');
16372                         Roo.debug && Roo.log(msg);
16373             if (!this.hideProgress &&  Roo.MessageBox) { 
16374                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16375             }
16376             
16377          
16378             // is the module disabled?
16379             var disabled = (typeof(m.disabled) == 'function') ?
16380                 m.disabled.call(m.module.disabled) : m.disabled;    
16381             
16382             
16383             if (disabled) {
16384                 return progressRun(); // we do not update the display!
16385             }
16386             
16387             // now build 
16388             
16389                         
16390                         
16391             m.render();
16392             // it's 10 on top level, and 1 on others??? why...
16393             return progressRun.defer(10, _this);
16394              
16395         }
16396         progressRun.defer(1, _this);
16397      
16398         
16399         
16400     },
16401         
16402         
16403         /**
16404          * Event Object.
16405          *
16406          *
16407          */
16408         event: false, 
16409     /**
16410          * wrapper for event.on - aliased later..  
16411          * Typically use to register a event handler for register:
16412          *
16413          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16414          *
16415          */
16416     on : false
16417    
16418     
16419     
16420 });
16421
16422 Roo.XComponent.event = new Roo.util.Observable({
16423                 events : { 
16424                         /**
16425                          * @event register
16426                          * Fires when an Component is registered,
16427                          * set the disable property on the Component to stop registration.
16428                          * @param {Roo.XComponent} c the component being registerd.
16429                          * 
16430                          */
16431                         'register' : true,
16432             /**
16433                          * @event beforebuild
16434                          * Fires before each Component is built
16435                          * can be used to apply permissions.
16436                          * @param {Roo.XComponent} c the component being registerd.
16437                          * 
16438                          */
16439                         'beforebuild' : true,
16440                         /**
16441                          * @event buildcomplete
16442                          * Fires on the top level element when all elements have been built
16443                          * @param {Roo.XComponent} the top level component.
16444                          */
16445                         'buildcomplete' : true
16446                         
16447                 }
16448 });
16449
16450 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16451